2013-04-17 5 views
26

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

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

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

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

+0

Я планировал сделать это ... копировать все это на другой сервер и только запускать по одной штуке за раз и посмотреть, что вызывает ее. Дорогой и отнимающий много времени, хотя ... Не существует способов модульной тестовой памяти в PHP? – Guy

+0

Нет, я знаю. Мне тоже любопытно. Я проголосовал за тебя, и, возможно, мы оба узнаем. –

+0

Я согласен с @ TomášZato.Вы можете использовать скрипт 'auto_append_file' и методы' memory_get_ *', чтобы записывать все ваши скрипты и следить за тяжелыми. – metadings

ответ

19

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

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

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

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

+0

Что относительно ссылочных варов? –

1

Я не эксперт по использованию памяти, но, возможно, этот метод поможет вам обнаружить проблемные сценарии:

Получить информацию: 1. Используйте доступ апача файлов журнал 2. Создайте собственное потребление памяти log file (http://www.webhostingtalk.com/showthread.php?t=617742)

Проверьте время, когда использование памяти увеличивается и сравнивается с журналом доступа apache.

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

Удачи вам!

5

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

  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. Run google-pprof сравнения 2 дампы памяти:

    google-pprof --web --base=/tmp/profile_17.heap /tmp/profile_18.heap 
    

    Это позволит открыть SVG изображения, как это в вашем браузере:

    sample from doc

    Описание номеров и имен внутри вы можете найти в gperftools documentation

P.S. Фиксация утечек на уровне php не гарантирует, что утечки памяти в интерпретаторе отсутствуют. В моем случае я заканчиваю тем, что перезапускал sctipt в более длительные периоды.

+0

Как это исправить? 'Не удалось получить количество символов из http: /// pprof/symbol' – user2264941

Смежные вопросы