сборка мусора php во время выполнения скрипта


У меня есть PHP-скрипт, работающий на cron, выполнение которого может занять до 15 минут. Через регулярные промежутки времени он выплевывает memory_get_usage(), чтобы я мог видеть, что происходит. В первый раз, когда он сообщает мне о моем использовании, я нахожусь на уровне 10 мегабайт. Когда сценарий заканчивается, я нахожусь на уровне 114 мегабайт!

Выполняет ли PHP сборку мусора во время выполнения скрипта? Или что происходит со всей этой памятью? Есть ли что-то, что я могу сделать, чтобы принудительно собрать мусор? Задача, которую выполняет мой сценарий, заключается в следующем еженощный импорт пары тысяч узлов в Drupal. Так что он делает одно и то же много раз.

Есть какие-нибудь предложения?

Author: Icode4food, 2010-06-24

4 answers

Ключ в том, что вы отменяете свои глобальные переменные, как только они вам не нужны.

Вам не нужно явно вызывать unset для локальных переменных и свойств объекта, потому что они уничтожаются, когда функция выходит за пределы области действия или объект уничтожается.

PHP сохраняет количество ссылок для всех переменных и уничтожает их (в большинстве условий), как только это количество ссылок становится равным нулю. Объекты имеют один внутренний счетчик ссылок и сами переменные ( ссылки на объекты) у каждого есть один счетчик ссылок. Когда все ссылки на объекты будут уничтожены, потому что их ссылки достигли 0, сам объект будет уничтожен. Пример:

$a = new stdclass; //$a zval refcount 1, object refcount 1
$b = $a;           //$a/$b zval refcount 2, object refcount 1
//this forces the zval separation because $b isn't part of the reference set:
$c = &$a;          //$a/$c zval refcount 2 (isref), $b 1, object refcount 2
unset($c);         //$a zval refcount 1, $b 1, object refcount 2
unset($a);         //$b refcount 1, object refcount 1
unset($b);         //everything is destroyed

Но рассмотрим следующий сценарий:

class A {
    public $b;
}
class B {
    public $a;
}

$a = new A;
$b = new B;
$a->b = $b;
$b->a = $a;
unset($a); //cannot destroy object $a because $b still references it
unset($b); //cannot destroy object $b because $a still references it

Эти циклические ссылки являются тем местом, где запускается сборщик мусора PHP 5.3. Вы можете явно вызвать сборщик мусора с помощью gc_collect_cycles.

Смотрите также Основы подсчета ссылок и Циклы сбора в руководство.

 16
Author: Artefacto, 2010-06-24 16:31:58

PHP сборка мусора в значительной степени является счетчиком ссылок (у него есть некоторое обнаружение циклов). Если вы сохраняете ссылки, которые все еще доступны, они легко сложатся, если не будут освобождены.

Используйте unset(), чтобы освободить переменные, которые вы больше не используете. Если вы просто перезапишете переменные (например, с помощью null), это позволит только GC уменьшить объем пространства, требуемого этой переменной, но не так сильно, как unset, что фактически позволяет уничтожить указанное значение.

Вы также должны надлежащим образом освободить любые ресурсы и т.д., которые вы используете.

Вы все равно увидите увеличение объема памяти во время выполнения, поскольку GC может освободить ее по своему усмотрению, например, когда есть свободные циклы процессора или когда у него начинает заканчиваться память.

 3
Author: Fish, 2010-06-24 13:43:06

Используйте unset() как можно чаще, чаще проверяйте используемую память. да, php выполняет сборку мусора во время выполнения при нескольких условиях. вот полезный пост на php.net .

 2
Author: Sergey Eremin, 2016-02-21 02:55:49

Если объем памяти увеличивается настолько сильно, то вы, вероятно, не освобождаете ее. Вы создали утечку памяти. Сборка мусора не поможет вам, если вы не отмените установку переменных, не уничтожите объекты и/или они не выйдут за рамки.

Вы отключаете узлы, которые загружаете, как только закончите с ними? Я написал PHP-скрипты, которые работают часами, обрабатывая миллионы записей базы данных, без проблем и с использованием памяти, которая увеличивается и уменьшается в очень приемлемом диапазоне.

 1
Author: Brent Baisley, 2010-06-24 13:23:43