1. Что такое сборка мусора и зачем она нужна?
Сборка мусора (Garbage Collection, GC) — это автоматическое освобождение памяти, которую программа больше не использует.
Без GC разработчикам приходилось бы вручную освобождать память (как в C/C++ с malloc/free
).
С GC PHP сам определяет, когда объекты больше не нужны, и очищает их.
Зачем это нужно?
- Избегать утечек памяти
- Упрощать разработку (не нужно следить за каждым объектом)
- Повышать стабильность долгоживущих процессов (например, PHP-FPM)
2. Как PHP управляет памятью?
PHP использует гибридный подход:
- Референсный подсчет (Reference Counting) – основной механизм.
- Циклический сборщик (Cycle Collector) – для сложных случаев.
Как работает референсный подсчет?
- Каждая переменная (
zval
) хранит счетчик ссылок (refcount
). - Когда
refcount
достигает0
, память освобождается мгновенно.
Пример:
$a = new stdClass(); // refcount = 1
$b = $a; // refcount = 2
unset($a); // refcount = 1
unset($b); // refcount = 0 → память освобождена
Когда референсного подсчета недостаточно?
При циклических ссылках (когда объекты ссылаются друг на друга):
$a = new stdClass();
$b = new stdClass();
$a->child = $b; // $a ссылается на $b
$b->parent = $a; // $b ссылается на $a
unset($a, $b); // refcount останется = 1 → утечка!
Здесь на помощь приходит циклический сборщик.
3. Референсный подсчет vs. Tracing GC (как в Java/C#)
Критерий | PHP (Reference Counting) | Java/C# (Tracing GC) |
---|---|---|
Скорость | Быстро (освобождает сразу) | Медленнее (сканирует всю память) |
Память | Тратит меньше ОЗУ | Требует больше памяти |
Задержки | Нет «stop-the-world» | Возможны паузы (GC STW) |
Циклические ссылки | Требует отдельный сборщик | Находит автоматически |
Вывод:
- Референсный подсчет быстрее, но не справляется с циклами.
- Tracing GC (как в Java) универсальнее, но требует больше ресурсов.
4. Когда включается GC в PHP?
GC в PHP работает в два этапа:
- Мгновенное освобождение (при
refcount=0
). - Циклический сборщик (запускается при условиях):
Когда срабатывает циклический сборщик?
- При достижении порога (по умолчанию
10 000
потенциальных циклов). - При вызове
gc_collect_cycles()
(ручной запуск). - При завершении скрипта (если
gc_enable=On
).
Настройки в php.ini
:
zend.enable_gc = On ; Включить GC
gc_probability = 1 ; Вероятность запуска (1/100)
gc_divisor = 100
gc_max_roots = 10000 ; Порог для активации
5. Краткий обзор изменений в PHP 8.3
В PHP 8.3 GC получил небольшие оптимизации:
- Уменьшены накладные расходы на отслеживание ссылок.
- Улучшена интеграция с JIT (меньше пауз при сборке).
- Оптимизирован алгоритм обхода объектов (быстрее на сложных графах).
Что не изменилось:
- Основной механизм (референсный подсчет + циклы).
- API (
gc_enable()
,gc_collect_cycles()
) остался прежним.
Вывод
- PHP использует референсный подсчет для быстрого освобождения памяти.
- Циклический сборщик чинит утечки из-за взаимных ссылок.
- В PHP 8.3 GC стал немного быстрее, но принцип работы не изменился.
Следующая статья: Референсный подсчет в PHP — как именно работает refcount
? 🚀