Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

  • Если вам понадобится script для непрерывного запуска, вы можете подумать о другом подходе. Попробуйте выполнить while(true), но оберните supervisor (http://supervisord.org) вокруг своего script и позвольте ему вызываться после его завершения. Таким образом, вы на 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. Если вы используете Framework, например ZF или Symfony, это может быть невозможно, так как вы нарушите функциональность, если вы это сделаете.

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

Ответ 3

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

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

    sudo pecl install memprof

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

    sudo apt-get install google-perftools

  • Добавьте этот код в начало вашего script:

    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-изображение, подобное этому в вашем браузере:

    sample from doc

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

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

Ответ 4

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

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

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

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

Удачи!