There is a possibility to get GC performance stats without PHP recompilation. Starting from Xdebug version 2.6 you are able to enable stats collection into the file (default dir /tmp with name gcstats.%p):
php -dxdebug.gc_stats_enable=1 your_script.phpРазгледувања за перформансите
Почист и полокален преглед на PHP референцата, со задржана структура од PHP.net и подобра читливост за примери, секции и белешки.
Разгледувања за перформансите
Референца за `features.gc.performance-considerations.php` со подобрена типографија и навигација.
Разгледувања за перформансите
We have already mentioned in the previous section that simply collecting the possible roots had a very tiny performance impact, but this is when you compare PHP 5.2 against PHP 5.3. Although the recording of possible roots compared to not recording them at all, like in PHP 5.2, is slower, other changes to the PHP runtime in PHP 5.3 prevented this particular performance loss from even showing.
Веќе споменавме во претходниот дел дека едноставното собирање на можни корени имаше многу мало влијание на перформансите, но ова е кога споредувате PHP 5.2 со PHP 5.3. Иако снимањето на можни корени во споредба со нивното воопшто да не се снима, како во PHP 5.2, е побавно, другите промени во PHP runtime во PHP 5.3 спречија овој конкретен губиток на перформансите дури и да се покаже.
Постојат две главни области во кои се влијае на перформансите. Првата област е намалена потрошувачка на меморија, а втората област е времето на извршување кога механизмот за собирање отпадоци ги врши своите чистења на меморијата. Ќе ги разгледаме и двата проблеми.
Намалена потрошувачка на меморија gc_collect_cycles() Пред сè, целата причина за имплементирање на механизмот за собирање отпадоци е да се намали потрошувачката на меморија со чистење на променливи со кружни референци веднаш штом ќе се исполнат предусловите. Во имплементацијата на PHP, ова се случува веднаш штом ќе се наполни тампонот за корени, или кога функцијата
се повикува. Во графикот подолу, прикажуваме потрошувачка на меморија на скриптата подолу, и во PHP 5.2 и во PHP 5.3, исклучувајќи ја основната меморија што самиот PHP ја користи при стартување.
<?php
class Foo
{
public $var = '3.14159265359';
public $self;
}
$baseMemory = memory_get_usage();
for ( $i = 0; $i <= 100000; $i++ )
{
$a = new Foo;
$a->self = $a;
if ( $i % 500 === 0 )
{
echo sprintf( '%8d: ', $i ), memory_get_usage() - $baseMemory, "\n";
}
}
?>
Пример #1 Пример за потрошувачка на меморија $a Во овој многу академски пример, создаваме објект во кој својство е поставено да укажува назад кон самиот објект. Кога
променливата во скриптата повторно се доделува во следната итерација на циклусот, типично би се појавил истекување на меморија. Во овој случај, се истекуваат два zval-контејнери (zval објектот и zval својството), но се наоѓа само еден можен корен: променливата што беше откажана. Кога тампонот за корени ќе се наполни по 10.000 итерации (со вкупно 10.000 можни корени), механизмот за собирање отпадоци се активира и ја ослободува меморијата поврзана со тие можни корени. Ова многу јасно може да се види во назалбениот графикон за потрошувачка на меморија за PHP 5.3. По секои 10.000 итерации, механизмот се активира и ја ослободува меморијата поврзана со променливите со кружни референци. Самиот механизам не мора да врши многу работа во овој пример, бидејќи структурата што се истекува е исклучително едноставна. Од дијаграмот, гледате дека максималната потрошувачка на меморија во PHP 5.3 е околу 9 Mb, додека во PHP 5.2 потрошувачката на меморија продолжува да се зголемува.
Забавувања при извршување
Втората област каде што механизмот за собирање отпадоци влијае на перформансите е времето потребно кога механизмот за собирање отпадоци се активира за да ја ослободи „истечената“ меморија. За да видиме колку е ова, малку го менуваме претходниот скрипт за да дозволиме поголем број итерации и отстранување на меѓусебните податоци за потрошувачка на меморија. Вториот скрипт е тука:
<?php
class Foo
{
public $var = '3.14159265359';
public $self;
}
for ( $i = 0; $i <= 1000000; $i++ )
{
$a = new Foo;
$a->self = $a;
}
echo memory_get_peak_usage(), "\n";
?>Пример #2 Влијанија на перформансите на GC zend.enable_gc Ќе го извршиме овој скрипт двапати, еднаш со
поставката вклучена, и еднаш со исклучена:
time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php # and time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php
Пример #3 Извршување на горниот скрипт
На мојата машина, првата команда се чини дека конзистентно трае околу 10,7 секунди, додека втората команда трае околу 11,4 секунди. Ова е забавување од околу 7%. Сепак, максималната количина на меморија што ја користи скриптата е намалена за 98% од 931Mb на 10Mb. Овој бенчмарк не е многу научен, ниту пак репрезентативен за реални апликации, но покажува придобивките од потрошувачката на меморија што ги нуди овој механизам за собирање отпадоци. Доброто е што забавувањето секогаш е истото 7%, за овој конкретен скрипт, додека можностите за заштеда на меморија заштедуваат сè повеќе меморија како што се наоѓаат повеќе кружни референци за време на извршувањето на скриптата.
Внатрешна статистика на GC на PHP CFLAGS
Можно е да се добијат малку повеќе информации за тоа како се извршува механизмот за собирање отпадоци од внатрешноста на PHP. Но, за да го направите тоа, ќе мора повторно да го компилирате PHP за да ги овозможите кодовите за бенчмаркинг и собирање податоци. Ќе мора да го поставите -DGC_BENCH=1 променливата на околината на
./configure пред да го извршите
Веќе споменавме во претходниот дел дека едноставното собирање на можни корени имаше многу мало влијание на перформансите, но ова е кога ја споредувате PHP 5.2 со PHP 5.3. Иако снимањето на можни корени во споредба со нивното воопшто да не се снима, како во PHP 5.2, е побавно, другите промени во PHP runtime во PHP 5.3 спречија овој конкретен загуба на перформанси дури и да се покаже.
export CFLAGS=-DGC_BENCH=1 ./config.nice make clean make
Пример #4 Повторно компилирање на PHP за овозможување на GC бенчмаркинг
Кога повторно ќе го стартувате горниот пример со новоизградениот PHP бинарен, ќе го видите следново прикажано откако PHP ќе заврши со извршување:
GC Statistics
-------------
Runs: 110
Collected: 2072204
Root buffer length: 0
Root buffer peak: 10000
Possible Remove from Marked
Root Buffered buffer grey
-------- -------- ----------- ------
ZVAL 7175487 1491291 1241690 3611871
ZOBJ 28506264 1527980 677581 1025731
Пример #5 GC статистики
Пример #4 Прекомпилирање на PHP за овозможување GC бенчмаркинг
Кога повторно ќе го стартувате горниот примерен код со новоизградениот PHP бинарен, ќе го видите следново прикажано откако PHP ќе заврши со извршување:
Пример #5 GC статистики
Најинформативните статистики се прикажани во првиот блок. Овде можете да видите дека механизмот за собирање отпад се извршил 110 пати, и вкупно, повеќе од 2 милиони мемориски алокации беа ослободени за време на тие 110 извршувања. Штом механизмот за собирање отпад се извршил барем еднаш, „Root buffer peak“ секогаш е 10000. Заклучок Генерално, собирачот на отпад во PHP ќе предизвика забавување само кога алгоритмот за собирање циклуси навистина се извршува, додека во нормални (помали) скрипти не треба да има никакво влијание врз перформансите.
Белешки од корисници 2 забелешки
The GC, unfortunately, as expounded in the examples above, has the tendency to promote lazy programming.
Clearly the benefits of the GC to assist in memory management are there, and help to maintain a stable system, but it is no excuse to not plan and test your code properly.
Always re-read your code critically and objectively to ensure that you are not introducing memory leaks unintentionally.