Введение в сборку мусора в PHP

1. Что такое сборка мусора и зачем она нужна?

Сборка мусора (Garbage Collection, GC) — это автоматическое освобождение памяти, которую программа больше не использует.

Без GC разработчикам приходилось бы вручную освобождать память (как в C/C++ с malloc/free).

С GC PHP сам определяет, когда объекты больше не нужны, и очищает их.

Зачем это нужно?

  • Избегать утечек памяти
  • Упрощать разработку (не нужно следить за каждым объектом)
  • Повышать стабильность долгоживущих процессов (например, PHP-FPM)

2. Как PHP управляет памятью?

PHP использует гибридный подход:

  1. Референсный подсчет (Reference Counting) – основной механизм.
  2. Циклический сборщик (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 работает в два этапа:

  1. Мгновенное освобождение (при refcount=0).
  2. Циклический сборщик (запускается при условиях):

Когда срабатывает циклический сборщик?

  • При достижении порога (по умолчанию 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? 🚀

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *