Мой выделенный сервер имеет 32 ГБ оперативной памяти, и память постоянно растет и постоянно растет, и я должен перезагружать ее ежедневно. Это стоит мне клиентов и денег.
Мне трудно найти, где утечка памяти. Все, что я могу найти в Интернете, – это люди, которые говорят «Использовать xdebug», но я не смог найти xdebug-учебники по обнаружению утечек памяти. Я пробовал печатать memory_get_usage до и после вызова функций, но это правильный способ сделать это?
У меня много запущенных скриптов php – некоторые из посетителей, другие из cron-заданий – и мне нужно найти, какой из них у них утечка памяти, и исправить его как можно скорее, но я даже не знаю, как определить, является ли данная функция утечка памяти или нет.
Я пробовал печатать memory_get_usage перед вызовом функции и после, и он поднимается вверх, но если я вызываю функцию более одного раза, она больше не растет. Может кто-нибудь объяснить это и рассказать мне, как я могу просто и легко сказать, есть ли у функции PHP утечка памяти?
Вы можете делать разные вещи, но сначала вы должны попытаться избежать создания утечек памяти в первую очередь.
Позвольте мне пояснить: 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(); } } } }
с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
. Если вы используете Framework, например 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(); }
И в этом месте вы оказались expexct, чтобы найти утечку памяти:
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
PS Устранение утечек на php-уровне не гарантирует, что утечки памяти в интерпретаторе отсутствуют. В моем случае я заканчиваю тем, что перезапускал sctipt в более длительные периоды.
Я не специалист по использованию памяти, но, возможно, этот метод поможет вам обнаружить проблемные скрипты:
Получение информации: 1. Используйте файлы журнала доступа apache. 2. Создайте свой собственный файл журнала использования памяти ( http://www.webhostingtalk.com/showthread.php?t=617742 ).
Проверьте время, когда использование памяти увеличивается и сравнивается с журналом доступа apache.
Он, по крайней мере, даст вам информацию о том, будет ли использование медленно и постоянным, или начнется в определенный момент.
Удачи!