Как узнать, в каком PHP-скрипте происходит утечка памяти?
Мой выделенный сервер имеет 32 ГБ оперативной памяти, и объем памяти постоянно увеличивается, и теперь мне приходится перезагружать его ежедневно. Это стоит мне клиентов и денег.
Мне трудно найти место утечки памяти. Все, что я могу найти в Интернете, это то, что люди говорят "Используйте xdebug", но я не смог найти никаких руководств по xdebug по поиску утечек памяти. Я пробовал печатать memory_get_usage до и после вызовов функций, но правильно ли это делать?
У меня МНОГО запущены php-скрипты - некоторые от посетителей, другие от заданий cron - и мне нужно найти, у кого из них происходит утечка памяти, и исправить это как можно скорее, но я даже не знаю, как определить, является ли данная функция утечкой памяти или нет.
Я пробовал печатать memory_get_usage до вызова функции и после, и он увеличивается, но затем, если я вызываю функцию более одного раза, он больше не увеличивается. Может кто-нибудь, пожалуйста, объяснить это и сказать мне, как я могу просто и легко определить, имеет ли функция PHP утечка памяти?
4 answers
Вы могли бы делать разные вещи, но сначала вы должны попытаться избежать создания утечек памяти в первую очередь.
Позвольте мне уточнить: PHP - это язык сценариев, и он не предназначен для длительных сценариев, поэтому его управление памятью не является лучшим на рынке. Но почему это должно быть так? Его цель состоит в том, чтобы вызываться на уровне запроса, поэтому область его выполнения довольно мала (не более 2-3 секунд). Все остальное должно быть отодвинуто на задний план.
Что я могу сделать против утечек памяти?
Если у вас версия ниже 5.4, вам необходимо позаботиться о ссылках на круги, так как они не являются собранным мусором.
Если вам нужен сценарий, который будет выполняться непрерывно, вы можете подумать о другом подходе. Попробуйте реализацию
while(true)
, но обернитеsupervisor
(http://supervisord.org ) вокруг вашего скрипта, и пусть он будет вызван после его завершения. Таким образом, вы на 100 % уверены, что у вас никогда не будет утечек памяти.Ты можно было бы использовать
xdebug
для профилирования ваших сценариев один за другим и выяснить, где потребляется много памяти.-
Вы можете реализовать деструктор, чтобы отменить все ваши ссылки, если класс больше не нужен.
public function __destruct(){ $this->cleanup(); } public function cleanup() { //cleanup everything from attributes foreach (get_class_vars(__CLASS__) as $clsVar => $_) { unset($this->$clsVar); } //cleanup all objects inside data array if (is_array($this->_data)) { foreach ($this->_data as $value) { if (is_object($value) && method_exists($value, 'cleanUp')) { $value->cleanUp(); } } } }
Прочитайте документацию PHP, касающуюся сборки мусора http://us3.php.net/manual/en/features.gc.php
Избегайте глобальных переменных, потому что они никогда не собираются как мусор и должны быть
unset
явно. Если вы используете фреймворк, такой как ZF или Symfony, это может быть невозможно, так как вы нарушите функциональность, если сделаете это.
И последнее, но не менее важное, я хочу еще раз подчеркнуть, PHP не подходит для длительных сценариев! Если у вас есть дела, которые нужно выполнять непрерывно, вам не следует ломать голову из-за утечек памяти в PHP, а потратьте время на изучение более сложного языка, такого как JAVA или C#.
Посмотрите на это php-расширение: https://github.com/arnaud-lb/php-memory-profiler . Вы сможете сбрасывать информацию в различных форматах и просто анализировать ее с помощью некоторых инструментов, таких как: Инструменты производительности Google, KCachegrind или qcachegrind.
Я нашел метод, который довольно хорошо работает для меня:
-
Установите расширение "php-memprof". В Ubuntu вы можете запустить:
sudo pecl install memprof
-
Установите "google-perftools". Снова для Ubuntu:
sudo apt-get install google-perftools
-
Добавьте этот код в начало вашего скрипта:
if (function_exists('memprof_enable')) { memprof_enable(); }
-
И в этом месте вы ожидали обнаружить утечку памяти:
if (function_exists("memprof_dump_pprof")) { $time = microtime(true); $f = fopen("/tmp/profile_$time.heap", "w"); memprof_dump_pprof($f); fclose($f); echo "Memory profile dumped. "; }
В моем случае это было внутри большого цикла каждые 100 бежит.
-
Запустите
google-pprof
сравнение 2 дампов памяти:google-pprof --web --base=/tmp/profile_17.heap /tmp/profile_18.heap
Это откроет в вашем браузере изображение svg следующим образом:
Описание номеров и имен внутри вы можете найти в документации gperftools
P.S. Исправление утечек на уровне php не гарантирует вам, что в интерпретаторе нет утечек памяти. В моем случае я заканчиваю просто перезапуском sctipt в более длительные периоды.
Я не эксперт по использованию памяти, но, возможно, этот метод поможет вам обнаружить проблемные сценарии:
Получить информацию: 1. Используйте файлы журнала доступа apache 2. Создайте свой собственный файл журнала использования памяти (http://www.webhostingtalk.com/showthread.php?t=617742)
Проверьте время увеличения использования памяти и сравните с журналом доступа apache.
Это, по крайней мере, даст вам информацию о том, растет ли использование медленно и постоянно или оно начинается с определенный момент.
Удачи!