Php найти утечку памяти

Диагностика утечек памяти. Допустимый размер памяти в # байт.

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

Увеличение лимита

Если вы знаете, что делаете и хотите увеличить лимит, см. Memory_limit :

ini_set('memory_limit', '16M'); ini_set('memory_limit', -1); // no limit 

Осторожно! Вы можете решить только симптом, а не проблему!

Диагностика утечки:

Сообщение об ошибке указывает на строку с циклом, который, как я полагаю, протекает или ненужно накапливает память. Я напечатал memory_get_usage() в конце каждой итерации и вижу, что число медленно растет, пока оно не достигнет предела:

foreach ($users as $user) < $task = new Task; $task->run($user); unset($task); // Free the variable in an attempt to recover memory print memory_get_usage(true); // increases over time > с foreach ($users as $user) < $task = new Task; $task->run($user); unset($task); // Free the variable in an attempt to recover memory print memory_get_usage(true); // increases over time > 

Для целей этого вопроса давайте предположим, что наихудший код спагетти, который можно вообразить, скрывается в глобальной области где-то в $user или Task .

Какие инструменты, PHP-трюки или отладка voodoo могут помочь мне найти и устранить проблему?

Solutions Collecting From Web of «Диагностика утечек памяти. Допустимый размер памяти в # байт.»

У PHP нет сборщика мусора. Он использует подсчет ссылок для управления памятью. Таким образом, наиболее распространенным источником утечек памяти являются циклические ссылки и глобальные переменные. Боюсь, если вы используете фреймворк, у вас будет много кода, чтобы его найти. Самый простой инструмент – выборочно разместить вызовы на memory_get_usage и сузить его до места, где протекает код. Вы также можете использовать xdebug для создания следа кода. Запустите код с трассировкой выполнения и show_mem_delta .

Читайте также:  Python pathlib полный путь

В php существует несколько возможных точек утечки памяти:

  • сам php
  • расширение php
  • Библиотека php, которую вы используете
  • ваш php-код

Трудно найти и исправить первые 3 без глубокой обратной инженерии или знания исходного кода php. Для последнего вы можете использовать бинарный поиск для кода утечки памяти с памятью_get_usage

Я заметил один раз в старом скрипте, что PHP будет поддерживать переменную «as» как в области видимости даже после моего цикла foreach. Например,

foreach($users as $user)< $user->doSomething(); > var_dump($user); // would output the data from the last $user 

Я не уверен, что будущие версии PHP исправлены или нет, так как я видел это. Если это так, вы можете unset($user) после doSomething() чтобы удалить его из памяти. YMMV.

Недавно я столкнулся с этой проблемой в приложении, под тем, что я собираю, чтобы быть похожими обстоятельствами. Скрипт, который работает в CLI PHP, который перебирает много итераций. Мой скрипт зависит от нескольких базовых библиотек. Я подозреваю, что причиной является определенная библиотека, и я потратил несколько часов напрасно, пытаясь добавить соответствующие методы деструкции в свои классы безрезультатно. Столкнувшись с длительным процессом преобразования в другую библиотеку (которая может оказаться той же проблемой), я придумал грубую работу по этой проблеме в моем случае.

В моей ситуации, в linux cli, я перебирал кучу пользовательских записей и для каждого из них создавал новый экземпляр нескольких классов, которые я создал. Я решил попробовать создать новые экземпляры классов с помощью PHP-метода exec, чтобы этот процесс выполнялся в «новом потоке». Вот действительно базовый пример того, что я имею в виду:

foreach ($ids as $id) < $lines=array(); exec("php ./path/to/my/classes.php $id", $lines); foreach ($lines as $line) < echo $line."\n"; >//display some output > 

Очевидно, что этот подход имеет ограничения, и нужно знать об опасности этого, поскольку было бы легко создать работу на кролике, однако в некоторых редких случаях это могло бы помочь преодолеть трудное место, пока не будет найдено лучшее исправление , как в моем случае.

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

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

Сохраните следующий фрагмент в файле, например, /usr/local/lib/php/strangecode_log_memory_usage.inc.php :

 register_shutdown_function('strangecode_log_memory_usage'); 

Используйте его, добавив следующее в httpd.conf:

php_admin_value auto_prepend_file /usr/local/lib/php/strangecode_log_memory_usage.inc.php 

Затем проанализируйте файл журнала в /var/log/httpd/php_memory_log

Возможно, вам понадобится touch /var/log/httpd/php_memory_log && chmod 666 /var/log/httpd/php_memory_log прежде чем ваш веб-пользователь сможет записать в файл журнала.

Недавно я заметил, что функции лямбда PHP 5.3 оставляют лишнюю память, используемую при их удалении.

for ($i = 0; $i < 1000; $i++) < //$log = new Log; $log = function() < return new Log; >; //unset($log); > с for ($i = 0; $i < 1000; $i++) < //$log = new Log; $log = function() < return new Log; >; //unset($log); > 

Я не уверен, почему, но, кажется, он принимает дополнительные 250 байт каждый лямбда даже после удаления функции.

Если то, что вы говорите о том, что PHP выполняет только GC после функции, истинно, вы можете обернуть содержимое цикла внутри функции в качестве обходного пути / эксперимента.

Одна огромная проблема, с которой я столкнулся, – это использовать create_function . Как и в лямбда-функциях, он оставляет генерируемое временное имя в памяти.

Другой причиной утечки памяти (в случае Zend Framework) является Zend_Db_Profiler. Убедитесь, что это отключено, если вы запускаете скрипты под Zend Framework. Например, я имел в своем приложении application.ini следующее:

resources.db.profiler.enabled = true resources.db.profiler.class = Zend_Db_Profiler_Firebug 

Запустив примерно 25 000 запросов + загрузок до этого, он довел память до хорошего 128 Мб (максимальный максимальный предел памяти).

resources.db.profiler.enabled = false 

этого было достаточно, чтобы держать его под 20 Mb

И этот скрипт запускался в CLI, но он создавал экземпляр Zend_Application и запускал Bootstrap, поэтому он использовал конфигурацию разработки.

Это действительно помогло запустить скрипт с профилированием xDebug

Я бы посоветовал вам проверить руководство php или добавить gc_enable() для сбора мусора … Это утечка памяти не влияет на то, как работает ваш код.

PS: php имеет сборщик мусора gc_enable() который не принимает аргументов.

Я немного опаздываю на этот разговор, но я расскажу кое-что, относящееся к Zend Framework.

У меня возникла проблема с утечкой памяти после установки php 5.3.8 (с использованием phpfarm) для работы с ZF-приложением, которое было разработано с помощью php 5.2.9. Я обнаружил, что утечка памяти запускалась в файле httpd.conf Apache, в моем определении виртуального хоста, где сказано SetEnv APPLICATION_ENV «development» . После комментирования этой строки утечки памяти прекратились. Я пытаюсь создать встроенный обходной путь в моем PHP-скрипте (главным образом, определяя его вручную в основном файле index.php).

Я не видел, чтобы это упоминалось здесь, но одна вещь, которая может быть полезна, – это использовать xdebug и xdebug_debug_zval (‘variableName’), чтобы просмотреть их.

Я также могу привести пример расширения php в пути: Z-Ray Zend Server. Если сбор данных разрешен, использование памяти будет накладываться на каждую итерацию так же, как если бы сбор мусора был отключен.

  • PHP Неустранимая ошибка: не удается наследовать абстрактную функцию
  • Альтернатива CURLOPT_RANGE для захвата определенного раздела
  • как обрабатывать ошибку 403 с помощью PHP
  • как отправить сообщение facebook другу через график api с помощью Accessstoken
  • Лучшая практика для PHP / MySQL Назначение / Система бронирования
  • Запись метаданных XMP в jpeg (с помощью PHP) – Использование одиночного или множественного rdf: Блоки описания
  • пример создания купона дисконтирования и погашения в php
  • Как работает PHP foreach?
  • Проблемы с записью в файл с PHP на Ubuntu
  • Переопределить функцию php по умолчанию? (Eval)
  • Получение PHP для запуска скрипта Python
  • Считать конкретные значения в многомерном массиве
  • $ не определен в JQuery
  • HTTP Request encrypt & decrypt failure с PHP и Objective-C
  • Исключить исключение «DOMException» с сообщением «Ошибка запроса иерархии»

Источник

Как определить причину утечки памяти в PHP скрипте?

Есть скрипт, который обрабатывает большое количество данных. Сделал unset переменных, которые больше не нужны на каждой итерации, но память продолжает утекать с бешеной скоростью. Есть ли способы определить источник утечки в коде?

Оценить 1 комментарий

Какие библиотеки используются?
Могут давать утечку классы по ресайзу картинок, хмл парсеры итп.
Если юзается phpQuery в цикле, то
phpQuery::unloadDocuments()

FanatPHP

Получать записи надо не массивом, а по одной.
И никакая память никуда утекать не будет. ДАЖЕ если не ансетить те переменные, которые и так будут перезаписаны при следующей итерации.

Я заметил существенную разницу в потреблении памяти после того, как сделал unset переменных, которые и так будут перезаписаны при следующей итерации
По поводу массива я огоровился. Конечно, я не записываю findAll в массив.

Однако я перебираю объекты с ссылкой и удаляю элемент из общего списка в конце итерации. Несмотря на то, что переменная будет перезаписана, общий список то увеличивается.

FanatPHP

«Не записываю в массив» но «удаляю из общего списка» — как это понимать? В общем, не держать в памяти больше одной записи -самый верный способ избежать «утечки» памяти.

FanatPHP

FanatPHP: он использует AR и устаревший фреймворк. Не грузи ему мозг.
AlexChebanenko: как варик разбей работу срипта на последовательности от 100 до 1000 итераций за раз. потом запускай занова, но с оффсетом на выполненные итерации.
память теряется в пхпквери. его уж тожно разбирать не будешь

FanatPHP

Максим Гречушников: Даже устаревший фреймворк позволяет не грузить все данные в память. Впрочем, все равно у него текла какая-то дремучая либа.

FanatPHP: ставлю 90% на пхпквери. за yii за 5 лет не видел проблем. на днях в связке с битриксом поймал. битрикс в методе ciblockelement::update херачит память куда то

К сожалению, не могу. Могу сказать лишь то, что это Yii 1, использую ACtiveRecord и phpQuery. Получаю массив записей из бд, каждая запись около 1-4 кб. Обрабатываю текст с помощью phpQuery, делаю записи в бд. Каждую итерацию удаляю все переменные, с которыми работал. Так же удаляю элемент из массива результатов.

Войдите, чтобы написать ответ

PHP — как отправить письмо с одного EMail на другой, с помощью SMTP+php?

Источник

Оцените статью