Питання продуктивності
У попередньому розділі нами вже говорилося, що простий збирання коренів менше впливає на продуктивність. Хоча запис коренів у буфер порівняно з повною відсутністю такий у PHP 5.2 працює повільніше, інші зміни в роботі PHP 5.3 зробили цю втрату продуктивності непомітною.
Є дві основні області, що впливають на продуктивність: зменшення розміру пам'яті, що використовується, і уповільнення роботи при складанні сміття. Розглянемо їх.
Зменшення розміру пам'яті, що використовується
Насамперед, основною причиною реалізації механізму складання сміття є зменшення розміру пам'яті, що використовується за допомогою чищення циклічних посилань, яка відбувається при досягненні відповідних умов. У реалізації PHP це відбувається, як тільки заповниться кореневий буфер або при виклику функції gc_collect_cycles(). На графіку нижче наведено використання пам'яті скрипта, запущеного в PHP 5.2 та PHP 5.3, без урахування пам'яті, що використовується самим PHP під час запуску.
Приклад #1 Приклад використання пам'яті
Loading...
У цьому дуже академічному прикладі ми створюємо об'єкт, властивість якого задається посиланням на сам об'єкт. Коли в скрипті в наступній ітерації циклу перевизначається змінна $a, відбувається типова витік пам'яті. В даному випадку зникають два контейнери zval (контейнер об'єкта і контейнер властивості об'єкта), але визначається лише один корінь - віддалена змінна. Як тільки пройдуть 10 000 ітерацій (максимально в кореневому буфері буде 10 000 коренів), то запуститься механізм складання сміття і пам'ять, що займається цим корінням, буде звільнена. Цей процес добре видно на графіку використання пам'яті для PHP 5.3: після кожних 10 000 ітерацій графік просідає. Сам собою механізм у цьому прикладі робить негаразд багато роботи, оскільки структура витоків дуже проста. З графіка видно, що максимальне використання пам'яті PHP 5.3 склало близько 9 Мб, тоді як у PHP 5.2 воно продовжує зростати.
Уповільнення роботи
Другою областю, де збирання сміття впливає на продуктивність, є втрата часу, коли збирач сміття звільняє пам'ять. Щоб зрозуміти ступінь цього впливу, ми трохи змінимо попередній скрипт, додавши більше ітерацій і проміжних змінних. Змінений скрипт:
Приклад #2 Вплив на продуктивність
Loading...
Запускаємо скрипт двічі: із включеною опцією zend.enable_gc і без неї.
Приклад #3 Запуск скрипту
time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
і
time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php
На тестовій машині перша команда виконується приблизно 10.7 секунд, а друга приблизно 11.4 секунди. Це приблизно на 7% повільніше. Однак, максимальне використання пам'яті скриптом зменшилося на 98% з 931 МБ до 10 МБ. Цей тест не дуже науковий, але він дійсно демонструє перевагу використання пам'яті, що забезпечується збирачем сміття. Також добре те, що уповільнення для цього скрипта завжди приблизно 7%, тоді як економія пам'яті збільшується все більше і більше при знаходженні нового сміття.
Внутрішня статистика збирача сміття
Можна отримати трохи більше інформації про те, як механізм збирання сміття виконується в PHP. Але для цього необхідно перезбирати PHP для включення тесту продуктивності та коду для додаткового збору даних. Необхідно встановити змінну оточення CFLAGS
в значение-DGC_BENCH=1
до виконання команди ./configure
з параметрами. Наступні команди повинні спрацювати:
Приклад #4 Складання PHP для включення тесту продуктивності GC
export CFLAGS=-DGC_BENCH=1 ./config.nice make clean make
При запуску вищенаведеного прикладу з оновленим PHP можна побачити наступну інформацію після завершення роботи скрипту:
Приклад #5 Статистика GC
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
Найбільш корисна статистика відображена у першому блоці. Можна побачити, що механізм складання сміття було запущено 110 разів, і було звільнено понад 2 мільйони записів у пам'яті. Якщо складання сміття було запущено хоча б раз, то максимальна кількість коренів у буфері завжди дорівнюватиме 10 000.
Висновок
В цілому, збирач сміття в PHP викличе відчутні уповільнення тільки під час безпосередньої роботи механізму складання циклічних посилань, тоді як у звичайних (невеликих) скриптах не повинно бути падіння продуктивності.
Однак у тих випадках, коли механізм складання повинен спрацьовувати і в звичайних скриптах, зниження пам'яті, що використовується, дозволяє одночасно працювати на сервері більшій їх кількості.
Переваги найбільш очевидні для скриптів, що довго працюють, таких як великі набори тестів або демони. Новий механізм також повинен знизити витоку пам'яті для додатків » PHP-GTK, які зазвичай виконуються довше, ніж веб-скрипти.