Intereting Posts

Как найти, какой PHP-скрипт утечка памяти?

Мой выделенный сервер имеет 32 ГБ оперативной памяти, и память постоянно растет и постоянно растет, и я должен перезагружать ее ежедневно. Это стоит мне клиентов и денег.

Мне трудно найти, где утечка памяти. Все, что я могу найти в Интернете, – это люди, которые говорят «Использовать xdebug», но я не смог найти xdebug-учебники по обнаружению утечек памяти. Я пробовал печатать memory_get_usage до и после вызова функций, но это правильный способ сделать это?

У меня много запущенных скриптов php – некоторые из посетителей, другие из cron-заданий – и мне нужно найти, какой из них у них утечка памяти, и исправить его как можно скорее, но я даже не знаю, как определить, является ли данная функция утечка памяти или нет.

Я пробовал печатать memory_get_usage перед вызовом функции и после, и он поднимается вверх, но если я вызываю функцию более одного раза, она больше не растет. Может кто-нибудь объяснить это и рассказать мне, как я могу просто и легко сказать, есть ли у функции PHP утечка памяти?

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

    Позвольте мне пояснить: PHP – это язык сценариев, и он не предназначен для длинных сценариев, поэтому управление памятью не является лучшим на рынке. Но почему это должно быть? Его цель – вызывать на уровне запроса, поэтому его рабочая область довольно мала (не более 2 – 3 секунд). Все остальное должно быть помещено в фоновом режиме.

    Что я могу сделать против утечек памяти?

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

    2. Если вам нужен сценарий для непрерывного запуска, вы можете подумать о другом подходе. Попробуйте while(true) реализацию, но оберните supervisor ( http://supervisord.org ) вокруг своего скрипта и позвольте ему вызываться после его завершения. Таким образом, вы на 100% уверены, что никогда не получите утечек памяти.

    3. Вы можете использовать xdebug для профилирования своих сценариев один за другим и выяснить, где потребляется много памяти.

    4. Вы могли бы реализовать деструктор, чтобы отменить все ссылки, если класс больше не нужен.

       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(); } } } } 
    5. Прочитайте документацию PHP по сборке мусора http://us3.php.net/manual/en/features.gc.php

    6. Избегайте глобальных переменных, потому что они никогда не собираются мусором и должны быть явно unset . Если вы используете Framework, например ZF или Symfony, это может быть невозможно, так как вы нарушите функциональность, если вы это сделаете.

    И последнее, но не в последнюю очередь я хочу еще раз подчеркнуть , PHP не подходит для длинных сценариев! Если у вас есть что делать, вам нужно постоянно работать, вы не должны рушиться головой с утечками памяти в PHP, но найдите время, чтобы изучить более сложный язык, такой как JAVA или C #.

    Посмотрите на это php-расширение: https://github.com/arnaud-lb/php-memory-profiler . Вы можете сбрасывать информацию в разных форматах и ​​просто анализировать ее с помощью некоторых инструментов, таких как: инструменты производительности Google , KCacheGrind или QCacheGrind .

    Я нашел метод, который работает очень хорошо для меня:

    1. Установите расширение « php-memprof ». Вы можете запустить Ubuntu:

      sudo pecl install memprof

    2. Установите « google-perftools ». Опять для Ubuntu:

      sudo apt-get install google-perftools

    3. Добавьте этот код в начало вашего скрипта:

       if (function_exists('memprof_enable')) { memprof_enable(); } 
    4. И в этом месте вы оказались 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 пробегов.

    5. Запустите 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.

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

    Удачи!