Где найти «низкую память» и «свободные циклы процессора» вызывает запуск сбора мусора на unset ()?

Я часто нахожу ссылки на следующую цитату, используемую при объяснении того, что PHP unset() не запускает «сборку мусора» немедленно, но только тогда, когда она считает нужным (выделение мое):

unset () делает то, что говорит его имя, – отключает переменную. Это не приводит к немедленному освобождению памяти. Сборщик мусора PHP будет делать это, когда он увидит припадки – по желанию, как только эти циклы процессора не будут нужны в любом случае, или еще до того, как скрипт закончится из памяти , что бы ни случилось раньше.

Если вы делаете $ any = null; то вы переписываете данные переменной. Вы могли бы освободить память / сократиться быстрее, но она может украсть циклы процессора из кода, который действительно нуждается в них раньше, что приведет к более длительному общему времени выполнения.

Я хочу знать, как работает код C для этого цикла «низкая память» и «свободный процессор», который запускает сборку мусора, и отличается ли она от PHP 5.2.x и PHP 5.3+.

Поэтому я загрузил исходные файлы C PHP 5.2.17 и попытался найти правильные разделы кода. Может быть, я просто слепой, или мои умения C слишком малы, но я не смог найти такой код.

Может кто-нибудь указать мне на надлежащие файлы C, пожалуйста?

EDIT :

При поиске примеров использования приведенной выше цитаты я понял что-то странное.

Некоторые примеры, например https://stackoverflow.com/a/584982/693207 , ссылаются на эту цитату, используя следующий URL-адрес для комментария на php.net: http://us2.php.net/manual/en /function.unset.php#86347 .

Просмотр этого URL-адреса показывает только верхнюю часть руководства unset() . Комментарий № 86347 отсутствует.

Проверка машины обратного пути показывает, что этот комментарий DID существует с октября 2008 года, но исчез в какой-то момент или после сентября 2012 года (причина неизвестна).

Может быть, эта цитата, и всегда была, просто неправильно?

Или есть кто-нибудь там, кто может указать мне на правильные файлы C?

Хорошо, так что пришло время для некоторых PHP Mythbusters! Пожалуйста, начните с чтения документации PHP о том, как работает сбор мусора, поскольку я собираюсь предположить некоторые предварительные знания о том, как это все работает:

  • Основы подсчета ссылок
  • Сбор циклов

Во втором документе конкретно объясняется, что запускает циклический сборщик мусора. Он не имеет ничего общего с «свободными циклами процессора» или «низкой памятью» – он полностью основан на количестве потенциальных объектов мусора, которые присутствуют:

Когда сборщик мусора включается, алгоритм поиска цикла, как описано выше, выполняется всякий раз, когда корневой буфер заполняется. Корневой буфер имеет фиксированный размер 10000 возможных корней.

То есть, циклический сборщик мусора запускается в любое время, когда определенное количество потенциально мусорных объектов накапливается, независимо от размера этих объектов. Проверка кода в zend_gc.c подтверждает это – там, конечно, ничего не происходит, проверяя общий объем свободной памяти, и, конечно же, нет ни одной из потоков, которая понадобилась бы для запуска GC в то время, когда процессор свободен. Поэтому я думаю, что мы можем назвать эту часть «разоренной».


Затем давайте посмотрим, какова реальная разница между $x = null и unset($x) . Во-первых, давайте подтвердим, что они делают то же самое, используя этот класс, как наш Buster Test Dummy:

 class NoisyDestructor { function __destruct() { print "Destructor called\n"; } } 

Теперь давайте посмотрим, какая разница между установкой переменной в значение null и unset() :

 $x = new NoisyDestructor(); print "Created\n"; $x = null; print "Nulled\n"; print "\n"; $x = new NoisyDestructor(); print "Created\n"; unset($x); print "Unset\n"; с $x = new NoisyDestructor(); print "Created\n"; $x = null; print "Nulled\n"; print "\n"; $x = new NoisyDestructor(); print "Created\n"; unset($x); print "Unset\n"; 

Когда мы запускаем это, мы видим:

 Created Destructor called Nulled Created Destructor called Unset 

Подожди минутку – это точно такая же последовательность для обоих! Между ними нет функциональной разницы. Теперь, как насчет производительности?

 class Thing { } $start = microtime(true); for ($i = 0; $i < 1e6; $i++) { $x = new Thing(); $x = null; } printf("%f sec for null\n", microtime(true) - $start); $start = microtime(true); for ($i = 0; $i < 1e6; $i++) { $x = new Thing(); unset($x); } printf("%f sec for unset\n", microtime(true) - $start); с class Thing { } $start = microtime(true); for ($i = 0; $i < 1e6; $i++) { $x = new Thing(); $x = null; } printf("%f sec for null\n", microtime(true) - $start); $start = microtime(true); for ($i = 0; $i < 1e6; $i++) { $x = new Thing(); unset($x); } printf("%f sec for unset\n", microtime(true) - $start); 

Теперь, используя мой ноутбук для тестирования, с PHP 5.4, я получаю:

 0.130396 sec for null 0.175086 sec for unset 

Мало того, что разница в производительности между установкой переменной на нуль и ее установкой довольно незначительна, учитывая, сколько раз нам приходилось запускать этот цикл, чтобы увидеть этот результат, но на самом деле это полная противоположность тому, что утверждал этот комментарий: unset() На 25% медленнее! Этот миф PHP был хорошо и действительно разорен.

BUSTED

TL; DR : Цитата, которую вы нашли, совершенно неверна. (По всей видимости, она была удалена из PHP.net по этой причине.)