Как работает сборщик мусора в PHP - PullRequest
4 голосов
/ 03 апреля 2012

У меня есть PHP-скрипт с большим количеством людей, который извлекает их данные из внешнего ресурса через SOAP, модифицирует данные и отправляет их обратно. Из-за размера деталей я увеличил объем памяти PHP до 128 МБ. Приблизительно после 4 часов работы (вероятно, потребуется 4 дня, чтобы запустить), он исчерпал память. Вот основы того, что он делает:

$people = getPeople();
foreach ($people as $person) {
    $data = get_personal_data();
    if ($data == "blah") {
        importToPerson("blah", $person);
    } else {
        importToPerson("else", $person);
    }
}

После исчерпания памяти и сбоя я решил инициализировать $ data до цикла foreach и, согласно top, использование памяти для процесса не превысило 7,8%, и он работал в течение 12 часов.

Итак, мой вопрос: не запускает ли PHP сборщик мусора для переменных, инициализированных внутри цикла, даже если они используются повторно? Если система освобождает память, а PHP еще не пометил ее как пригодную для использования, и в конечном итоге она снова выйдет из строя (сейчас я поднял ее до 256 МБ, поэтому я изменил 2 вещи и не уверен, что это исправило, возможно, я мог бы изменить свой Сценарий обратно, чтобы ответить на это, но не хочу ждать еще 12 часов, пока он не разберется, чтобы выяснить)?

Я не использую Zend Framework, поэтому другой вопрос, подобный этому, я не считаю уместным.

РЕДАКТИРОВАТЬ: На самом деле у меня нет проблем со сценарием или что он делает. На данный момент, что касается всей системной отчетности, у меня нет проблем. Этот вопрос касается сборщика мусора и того, как / когда он восстанавливает ресурсы в цикле foreach и / или как система сообщает об использовании памяти процессом php.

Ответы [ 2 ]

2 голосов
/ 03 апреля 2012

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

В большинстве случаев, когда странице не хватает памяти, а лимит достаточно высок (а 128 МБ невелик), возникает проблема с алгоритмом. Многие программисты PHP собирают структуру данных, а затем передают ее на следующий шаг, который перебирает структуру, обычно создавая другую. Вспенить, промыть, повторить. К сожалению, этот подход требует больших затрат памяти, и вы в конечном итоге создаете несколько копий своих данных в памяти. Два из действительно больших изменений в PHP 5 заключались в том, что объекты подсчитываются, а не копируются, и вся строковая подсистема была сделана намного быстрее. Но это все еще проблема.

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

Тем не менее, вы можете использовать этот подход к экономии памяти для части данных. Хитрость в том, что вы явно unset() ключевая переменная или две в конце цикла. Это должно восстановить пространство. Другой трюк с "наилучшей практикой" заключается в отказе от манипулирования данными цикла, которое не обязательно должно быть в цикле. Как вы, кажется, обнаружили.

Я запускал PHP-скрипты, которые требуют более 1 ГБ памяти. Вы можете установить ограничение памяти для скрипта, на самом деле, с помощью ini_set('memory_limit', '1G');

1 голос
/ 03 апреля 2012

Используйте memory_get_usage (), чтобы увидеть, что происходит? Можно было бы поместить его в цикл, чтобы увидеть поведение при распределении памяти. Вы пытались посмотреть на системный монитор или что-то еще, чтобы увидеть, сколько php памяти использует во время этого процесса?

...