Отслеживание использования памяти в PHP

Я пытаюсь отслеживать использование памяти script, обрабатывающей URL-адреса. Основная идея состоит в том, чтобы проверить наличие разумного буфера перед добавлением другого URL-адреса в мультипроцессор cURL. Я использую концепцию "roll cURL", которая обрабатывает данные URL-адресов, когда выполняется многопроцессор. Это означает, что я могу поддерживать N подключений активными, добавляя новый URL-адрес из пула каждый раз, когда существующий URL-адрес обрабатывается и удаляется.

Я использовал memory_get_usage() с некоторыми положительными результатами. Добавление флага real_usage помогло (не совсем понятно различие между "системной" памятью и памятью "emalloc", но система показывает большие числа). memory_get_usage() растет, когда URL-адреса добавляются, а затем вниз, поскольку набор URL-адресов исчерпан. Тем не менее, я просто превысил ограничение 32M, когда моя последняя проверка памяти была ~ 18M.

Я обследую использование памяти каждый раз, когда сигналы cURL multi возвращают запрос. Поскольку несколько запросов могут возвращаться в одно и то же время, существует вероятность того, что множество URL-адресов возвратит данные одновременно и фактически переведет использование памяти в 14M. Однако, если memory_get_usage() является точным, я предполагаю, что что происходит.

[ Обновление. Должно было запускать больше тестов, прежде чем спросить, я думаю, увеличен лимит памяти php (но оставил "безопасную" сумму одинаковой в script), а использование памяти, как сообщалось, прыгать снизу ниже моего лимита в пределах от 25М до 32М. Затем, как и ожидалось, медленно уменьшались как URL-адреса, которые не были добавлены. Но я оставлю вопрос: это правильный способ сделать это?]

Могу ли я доверять memory_get_usage() таким образом? Есть ли лучшие альтернативные методы для использования памяти (я видел, как некоторые скрипты анализируют вывод команд оболочки)?

Ответ 1

real_usage работает следующим образом:

Менеджер памяти Zend не использует системный malloc для каждого блока, в котором он нуждается. Вместо этого он выделяет большой блок системной памяти (с шагом 256 КБ, может быть изменен путем установки переменной среды ZEND_MM_SEG_SIZE) и управляет ею изнутри. Итак, есть два типа использования памяти:

  • Сколько памяти, которую двигатель взял из ОС ( "реальное использование" )
  • Какая часть этой памяти фактически использовалась приложением ( "внутреннее использование" )

Любой из них может быть возвращен memory_get_usage(). Какой из них более полезен для вас, зависит от того, что вы изучаете. Если вы ищете оптимизацию кода в определенных частях, "внутренняя" может быть более полезной для вас. Если вы отслеживаете использование памяти во всем мире, "реальный" будет более полезен. memory_limit ограничивает "реальный" номер, поэтому, как только все блоки, которые разрешены лимитом, берутся из системы, и диспетчер памяти не может выделить запрошенный блок, распределение не выполняется. Обратите внимание, что "внутреннее" использование в этом случае может быть меньше предела, но распределение по-прежнему может завершиться неудачей из-за фрагментации.

Кроме того, если вы используете инструмент отслеживания внешней памяти, вы можете установить это переменная среды USE_ZEND_ALLOC=0, которая отключит вышеуказанный механизм и заставит двигатель всегда использовать malloc(). Это будет иметь гораздо худшую производительность, но позволяет использовать инструменты отслеживания malloc.

См. также статью об этом диспетчере памяти, также есть примеры кода.

Ответ 2

Я также предполагаю, что memory_get_usage() безопасен, но я думаю, вы можете сравнить оба метода и решить для себя, вот функция, которая анализирует системные вызовы:

function Memory_Usage($decimals = 2)
{
    $result = 0;

    if (function_exists('memory_get_usage'))
    {
        $result = memory_get_usage() / 1024;
    }

    else
    {
        if (function_exists('exec'))
        {
            $output = array();

            if (substr(strtoupper(PHP_OS), 0, 3) == 'WIN')
            {
                exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output);

                $result = preg_replace('/[\D]/', '', $output[5]);
            }

            else
            {
                exec('ps -eo%mem,rss,pid | grep ' . getmypid(), $output);

                $output = explode('  ', $output[0]);

                $result = $output[1];
            }
        }
    }

    return number_format(intval($result) / 1024, $decimals, '.', '');
}

Ответ 3

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

Список Википедии

Benchmark

Тесты рассчитаны на 2 года, но вы получаете представление об увеличении производительности.

Если вам нужно, вы также можете увеличить лимит памяти в PHP, если у вас все еще есть проблемы даже с ускорителем. Откройте php.ini и найдите:

memory_limit = 32M;

и немного увеличьте его.