Столкнулся при экспорте большого количества файлов с проблемой утечки памяти при работе с массивами объектов. Упрощенно код выглядит так: Код (PHP): class Test_Class { private $a = null; public function __construct($a = null) { $this->a = $a; } public function __destruct() { unset($this->a); } } print 'Memory before: '.memory_get_usage(1).' <br>'; // 262 144 $a = []; for ($i=0; $i<600000; $i++) $a[] = new Test_Class($i); print 'Memory after create: '.memory_get_usage(1).' <br>'; // 129 761 280 for($i=0; $i < count($a); $i++) unset($a[$i]); unset($a); print 'Memory after: '.memory_get_usage(1).' <br>'; // 35 389 440 при очередной итерации память всё же заканчивается. Есть идеи как освободить занятую память? PHP, JavaScript, SQL и другой код пишите внутри тегов Код ( (Unknown Language)): [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
xdebug есть? Протрассируйте расход памяти им. PHP вполне может "на всякий случай" оставлять себе "страничку" в размере 25% от максимального расхода, чтобы компенсировать возможные скачки производительности, например.
xdubug умеет показывать чем именно занята память? Я пользуюсь другим отладчиком, в данном скрипте вижу что переменных у меня не осталось, но чем занята память он мне показать не может. 25% от максимального расхода это нормально, я бы с этим согласился, но он сжирает память на каждой подобной итерации, и при генерации очередного файла скрипт обваливается
То есть каждый раз добавляется 35 метров "мусора"? Добавлено спустя 6 минут 3 секунды: Умеет трассировать ее расход по времени и вызовам функций. Попробуй без деструктора.
Тоже сталкивался на больших объемах, принудительные unset`ы всего чего можно, деструкты и даже вызов gc не помогли. Память всё равно текла и на каком-то моменте резко падала производительность. Решил путем разбития на задачи: скажем, каждый процесс обрабатывает один файл и в зависимости от имеющихся ресурсов их можно стартовать либо по очереди, либо параллельно. Проблема перешла из области оперативки в область нагрузки на процессор, но это уже не так страшно ))
Ну это и мой дебагер может. Проблема в том что память заполняется данными, данные выгружаются в файл, потом вроде как всё что можно/нужно я делаю unset, но память не освобождается. Да, тоже пробовали по-разному: с деструкторами, без них, с присваиванием null в разных вариациях, с вызовом gc_collect_cycles - результат близок к нулю. Тоже сейчас склоняемся к костылю, который будет для этой сотни экспортов запускать сотню экземпляров скрипта, но это же ужас...
!!!!!!!!!!! может это как то поможет, может за место unset использовать в деструкторе: Код (PHP): $this->a = null; я где то видел, на одну переменную ссылаются две переменные (по ссылке), делается unset а по ссылкам все равно данные доступны, а вот если = null то все = null.
Я воспользовался http://symfony.com/doc/current/components/process.html, позволяет довольно удобно рулить этими экземлярами и запускать их асинхронно, после чего можно сделать while(true) и внутри контролировать происходящее, добивая процессы до нужного количества, собирая вывод в массивчик ну и потом все в лог для разбора. Других вариантов побороть утечки не нашел, если найдете альтернативный, напишите. Очень интересно )
Код (Text): $a = new SplFixedArray(600000); существенно уменьшает второй memory_get_usage(1). но в целом ситуацию с освобождением всей памяти не решает, к сожалению. думаю, дело в том что остается неосвобожденной память использованная самим менеждером памяти, гдето внутри себя. для технических нужд, так сказать. т.е. данные то успешно уничтожаются в конце, но остаются некие метаданные. зачем и почему - хз. но проблема в том, что пхп не дает нам встроенного решения.
Второй memory_get_usage не представляет проблемы - на одну такую итерацию памяти гарантированно хватает, проблема в том, что таких итераций больше сотни, и рано или поздно хвосты, остающиеся от уничтоженных массивов сжирают всю память. Видимо будем резать скрипт на части и запускать внутренний блок через cURL
Это и есть классическая утечка. Автор, а не с объектами, если простые массивы гонять, тоже течет? Чисто из интереса - это у самого пыха аллокатор кривой, или это проблемы его ООП-движка.
А ни кто не пробовал погонять на эту тему php7? Там вроде как обещают переписать всё это дело, ускорить производительность раза в полтора и всё такое )
Простой вопрос - у вас действительно случилась ошибка нехватки памяти, или вы просто циферки посмотрели и испугались?
Да, я посмотрел по коду PHP - падаем, когда real_usage не хватает. Хотя на самом деле память не кушается если смотреть данные по процессу (grep VM /proc/<pid>/status). Там по ходу она даже не течет, а какой-то косяк со счетчиком. Или же фича. В общем, причина не видна. Топикстартеру просто советую поднять лимит и посмотреть на реальное использование памяти. К слову, если его пример обернуть в цикл, то в какой-то момент у меня real_usage перестает расти. В общем баг в багтрекере есть уже с год, но движения по нему нет. 7.0 работает нормально.