Использовать метод отслеживания памяти методом

Мне еще предстоит найти элегантное решение для этого. У меня есть класс с методом, который я хочу отслеживать использование памяти без изменения функции:

class Example
{
    public function hello($name)
    {
        $something = str_repeat($name, pow(1024, 2));
    }
}

$class = new Example;
$class->hello('a');

Итак, задача в том, сколько памяти использует hello(), не мешая ей?

Примечание. Использование этого метода памяти должно быть 1 МБ. Я пробовал обернуть вызов с помощью memory_get_usage(); безрезультатно:

class Example
{
    public function hello($name)
    {
        $something = str_repeat($name, pow(1024, 2));
    }
}

$class = new Example;

$s = memory_get_usage();

$class->hello('a');

echo memory_get_usage() - $s;

Это приводит только к 144 байтам (не совсем правильно). Я пробовал различную магию с Reflection, используя класс ReflectionMethod.

У меня есть ощущение, что мне нужно сделать, это рассчитать разницу в методе:( Если кто-то может подумать о чем-нибудь более чистом, тогда вы действительно сделаете мой день.

Изменить: Я хотел бы упомянуть об этом в контексте приложения для бенчмаркинга. Таким образом, пока memory_get_peak_usage работает в том смысле, что он правильно возвращает использование памяти, он также будет искажать контрольные тесты, запущенные после метода высокой памяти. Теперь, если бы существовал способ reset статистики памяти, это тоже может быть полезно.

Ответ 1

Вы можете использовать register_tick_function и просто выгружать memeory_get_usage из каждого тика (строки) и анализировать его позже. Приведенный ниже класс можно улучшить, используя debug_backtrace, чтобы найти номер строки, относящийся к использованию памяти или добавляя время в строке с помощью microtime.

Класс Profiler

class Profiler
{

    private $_data_array = array();

    function __construct()
    {
        register_tick_function( array( $this, "tick" ) );
        declare(ticks = 1);
    }

    function __destruct()
    {
        unregister_tick_function( array( $this, "tick" ) );
    }

    function tick()
    {
        $this->_data_array[] = array(
            "memory" => memory_get_usage(),
            "time" => microtime( TRUE ),
            //if you need a backtrace you can uncomment this next line
            //"backtrace" => debug_backtrace( FALSE ),
        );
    }

    function getDataArray()
    {
        return $this->_data_array;
    }
}

Пример

class Example
{
    public function hello($name)
    {
        $something = str_repeat($name, pow(1024, 2));
    }
}

$profiler = new Profiler(); //starts logging when created

$class = new Example;
$class->hello('a');

$data_array = $profiler->getDataArray();

unset( $profiler ); //stops logging when __destruct is called

print_r( $data_array );

Выход

Array (
    [0] => Array (
            [memory] => 638088
            [time] => 1290788749.72
        )
    [1] => Array (
            [memory] => 638896
            [time] => 1290788749.72
        )
    [2] => Array (
            [memory] => 639536
            [time] => 1290788749.72
        )
    [3] => Array (
            [memory] => 640480
            [time] => 1290788749.72
        )
    [4] => Array (
            [memory] => 1689800 // <~ money!
            [time] => 1290788749.72
        )
    [5] => Array (
            [memory] => 641664
            [time] => 1290788749.72
        )
)

Возможная проблема

Поскольку этот класс профилировщика хранит данные в PHP, общее использование памяти будет увеличиваться искусственно. Одним из способов обойти эту проблему было бы записать данные в файл по ходу (сериализованному), и когда вы сделаете это, вы сможете его прочитать.

Ответ 2

Профайлер XHProfLive, разработанный ребятами из Facebook, дает такую ​​степень профилирования функций/методов и доступен как Загрузка PECL.

Ответ 3

Память освобождается при возврате из функции.

Вы можете добавить $s = memory_get_usage(); ... echo memory_get_usage() - $s; блокировать внутри функции. Таким образом, используемая память не будет выпущена.

Ответ 4

Похоже, что он уже "освободил" память после завершения вызова hello().

Каковы результаты, которые вы делаете:

$s = memory_get_usage();

$class->hello('a');

echo memory_get_peak_usage() - $s;

Ответ 6

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

Прочтите это:

http://www.xdebug.org/docs/profiler