Как определить размер памяти (размер) переменной?

Есть ли функция в PHP (или расширение PHP), чтобы узнать, сколько памяти использует данная переменная? sizeof просто сообщает мне количество элементов/свойств.

memory_get_usage помогает в том, что он дает мне размер памяти, используемый всем script. Есть ли способ сделать это для одной переменной?

Обратите внимание, что это находится на машине разработки, поэтому возможно загрузить расширения или инструменты отладки.

Ответ 1

Вам, вероятно, нужен Профайлер памяти. Я собрал информацию о SO, но я скопировал некоторые важные вещи, которые могут вам помочь.

Как вы, наверное, знаете, Xdebug отказался от поддержки профилирования памяти с версии 2. *. Пожалуйста, найдите здесь строку "удаленные функции": http://www.xdebug.org/updates.php

Удаленные функции

Удалена поддержка профилирования памяти, так как это не работает должным образом.

Другие параметры профилирования

PHP-памяти профилировщика

https://github.com/arnaud-lb/php-memory-profiler. Это то, что я сделал на моем сервере Ubuntu, чтобы включить его:

sudo apt-get install libjudy-dev libjudydebian1
sudo pecl install memprof
echo "extension=memprof.so" > /etc/php5/mods-available/memprof.ini
sudo php5enmod memprof
service apache2 restart

И затем в моем коде:

<?php
memprof_enable();
// do your stuff
memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));

Наконец откройте файл callgrind.out с помощью KCachegrind

Использование Google gperftools (рекомендуется!)

Прежде всего установите Google gperftools, загрузив последний пакет здесь: https://code.google.com/p/gperftools/

Тогда, как всегда:

sudo apt-get update
sudo apt-get install libunwind-dev -y
./configure
make
make install

Теперь в вашем коде:

memprof_enable();

// do your magic

memprof_dump_pprof(fopen("/tmp/profile.heap", "w"));

Затем откройте терминал и запустите:

pprof --web /tmp/profile.heap

pprof создаст новое окно в вашем существующем сеансе браузера, как показано ниже:

PHP memory profiling with memprof and gperftools

Xhprof + Xhgui (лучший, на мой взгляд, профиль как процессора, так и памяти)

С помощью Xhprof и Xhgui вы можете также профилировать использование процессора или просто использовать память, если это ваша проблема на данный момент. Это очень полные решения, они дают вам полный контроль, и журналы могут быть написаны как на mongo, так и в файловой системе.

Подробнее см. здесь.

Blackfire

Blackfire - это профилировщик PHP SensioLabs, ребята Symfony2 https://blackfire.io/

Если вы используете puphpet для настройки своей виртуальной машины, вы будете рады узнать, что она поддерживается; -)

Использование Xdebug и трассировки памяти

XDEBUG2 является расширением для PHP. Xdebug позволяет записывать все вызовы функций, включая параметры и возвращаемые значения в файл в разных форматах. Существует три формата вывода. Один из них предназначен для чтения человеком, а другой - для компьютерных программ, поскольку его легче разбирать, а последний использует HTML для форматирования трассировки. Вы можете переключаться между двумя различными форматами с настройкой. Примером может служить здесь

дляр

forp простой, неинтрузивный, ориентированный на производство, PHP-профайлер. Некоторые функции:

  • измерение времени и выделенной памяти для каждой функции

  • Использование ЦП

  • файл и номер строки вызова функции

  • вывод в формате Google Trace Event

  • подпись функций

  • группировка функций

  • псевдонимы функций (полезны для анонимных функций)

DBG

DBG - полнофункциональный отладчик php, интерактивный инструмент, который помогает вам отлаживать скрипты php. Он работает на WEB-сервере производства и/или разработки и позволяет отлаживать ваши сценарии локально или удаленно, из среды IDE или консоли, и его функции:

  • Удаленная и локальная отладка

  • Явная и неявная активация

  • Стек вызовов, включая вызовы функций, динамические и статические вызовы методов, с их параметрами

  • Навигация через стек вызовов с возможностью оценки переменных в соответствующих (вложенных) местах

  • Включение/выключение/Переход/Запуск функции курсора

  • Условные точки останова

  • Глобальные точки останова

  • Ведение журнала ошибок и предупреждений

  • Несколько одновременных сеансов для параллельной отладки

  • Поддержка интерфейсов GUI и CLI

  • Поддерживаются сети IPv6 и IPv4

  • Все данные, передаваемые отладчиком, могут быть дополнительно защищены SSL

Ответ 2

Нет прямого способа получить использование памяти одной переменной, но, как предложил Гордон, вы можете использовать memory_get_usage. Это вернет общий объем выделенной памяти, поэтому вы можете использовать обходной путь и измерять использование до и после, чтобы получить использование одной переменной. Это немного хаки, но он должен работать.

$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;

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

Фактически вы можете превратить это в функцию, создав копию переменной внутри функции и измерив используемую память. Не проверял это, но в принципе я не вижу в этом ничего плохого:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $tmp = unserialize(serialize($var));
    return memory_get_usage() - $start_memory;
}

Ответ 3

Нет, нет. Но вы можете serialize($var) и проверить strlen результата для приближения.

Ответ 4

Отвечая на вопрос Тату Ульманенса:

Следует отметить, что $start_memory сам займет память (PHP_INT_SIZE * 8).

Таким образом, вся функция должна стать:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $var = unserialize(serialize($var));
    return memory_get_usage() - $start_memory - PHP_INT_SIZE * 8;
}

Извините, что добавьте это как дополнительный ответ, но я пока не могу прокомментировать ответ.

Обновление: * 8 не определено. Это может зависеть, по-видимому, от версии php и, возможно, 64/32 бит.

Ответ 5

См:

Обратите внимание, что это не даст вам использование памяти определенной переменной.

Вы также можете взглянуть на расширение PECL Memtrack, хотя документации немного не хватает, если не сказать, -existent.

Ответ 6

Вы не можете ретроспективно рассчитать точный след переменной, поскольку две переменные могут совместно использовать одно и то же выделенное пространство в памяти

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

echo memory_get_usage()."\n"; // <-- 433200
$c=range(1,100);
echo memory_get_usage()."\n"; // <-- 444348 (+11148)
$d=array_slice($c, 1);
echo memory_get_usage()."\n"; // <-- 451040 (+6692)
unset($c);
echo memory_get_usage()."\n"; // <-- 444232 (-6808)
unset($d);
echo memory_get_usage()."\n"; // <-- 433200 (-11032)

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

Для получения полного представления о том, как выделена память в PHP и для чего она используется, я предлагаю вам прочитать следующую статью: Насколько велики массивы PHP ( и ценности) на самом деле? (Подсказка: БОЛЬШОЙ!)

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

Различные решения, представленные здесь, хороши для аппроксимаций, но никто не может справиться с тонким управлением памятью PHP.

  • вычисление вновь выделенного пространства

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

// open output buffer
echo "Result: ";
// call every function once
range(1,1); memory_get_usage();

echo memory_get_usage()."\n";
$c=range(1,100);
echo memory_get_usage()."\n";

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

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

  1. вычисление необходимого пространства

Если вы хотите полагаться на функцию для вычисления необходимого пространства для хранения копии переменной, следующий код выполняет различные оптимизации:

<?php
function getMemorySize($value) {
    // existing variable with integer value so that the next line
    // does not add memory consumption when initiating $start variable
    $start=1;
    $start=memory_get_usage();
    // json functions return less bytes consumptions than serialize
    $tmp=json_decode(json_encode($value));
    return memory_get_usage() - $start;
}

// open the output buffer, and calls the function one first time
echo ".\n";
getMemorySize(NULL);

// test inside a function in order to not care about memory used
// by the addition of the variable name to the $_GLOBAL array
function test() {
    // call the function name once 
    range(1,1);

    // we will compare the two values (see comment above about initialization of $start)
    $start=1;
    $start=memory_get_usage();
    $c=range(1,100);
    echo memory_get_usage()-$start."\n";
    echo getMemorySize($c)."\n";
}
test();

// same result, this works fine.
// 11044
// 11044

Обратите внимание, что размер имени переменной имеет значение в выделенной памяти.

  1. Проверьте свой код!

Переменная имеет базовый размер, определяемый внутренней структурой C, используемой в исходном коде PHP. Этот размер не изменяется в случае чисел. Для строк это добавит длину строки.

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value */
    zend_object_value obj;
} zvalue_value;

Если мы не учитываем инициализацию имени переменной, мы уже знаем, сколько переменной использует (в случае чисел и строк):

44 байта в случае чисел

& плюс; 24 байта в случае строк

& плюс; длина строки (включая конечный символ NUL)

(эти числа могут меняться в зависимости от версии PHP)

Вам необходимо округлить до нескольких байтов из-за выравнивания памяти. Если переменная находится в глобальном пространстве (не внутри функции), она также выделяет еще 64 байта.

Итак, если вы хотите использовать один из кодов внутри этой страницы, вам нужно проверить, соответствуют ли результаты с помощью простых тестовых примеров (строк или чисел) эти данные с учетом каждого из показаний в этом сообщении ($ Массив _GLOBAL, первый вызов функции, выходной буфер,...)

Ответ 7

Вы можете выбрать для вычисления разницы в памяти для возвращаемого значения обратного вызова. Это более элегантное решение, доступное в PHP 5.3 +.

function calculateFootprint($callback) {
    $startMemory = memory_get_usage();
    $result = call_user_func($callback);
    return memory_get_usage() - $startMemory;
}

$memoryFootprint = calculateFootprint(
    function() {
        return range(1, 1000000);
    }
);

echo ($memoryFootprint / (1024 * 1024)) . ' MB' . PHP_EOL;

Ответ 8

У меня была аналогичная проблема, и решение, которое я использовал, состояло в том, чтобы записать переменную в файл, а затем запустить файлize(). Примерно так же (непроверенный код):

function getVariableSize ( $foo ) 
{
    $tmpfile = "temp-" . microtime(true) . ".txt";
    file_put_contents($tmpfile, $foo);
    $size = filesize($tmpfile);
    unlink($tmpfile);
    return $size;
}

Это решение не очень быстро, потому что оно связано с диском IO, но оно должно дать вам нечто гораздо более точное, чем трюки memory_get_usage. Это зависит от того, насколько вам необходима точность.

Ответ 9

Никогда не пробовал, но трассировки Xdebug с xdebug.collect_assignment могут быть достаточно.

Ответ 10

function mesure($var){
    $start = memory_get_usage();
    if(is_string($var)){
        $newValue = $var . '';
    }elseif(is_numeric($var)){
        $newValue = $var + 0;
    }elseif(is_object($var)){
        $newValue = clone $var;
    }elseif(is_array($var)){
        $newValue = array_flip($var, []);
    }
    return memory_get_usage() - $start;
}

Ответ 11

Следующий script показывает общее использование памяти одной переменной.

function getVariableUsage($var) {
  $total_memory = memory_get_usage();
  $tmp = unserialize(serialize($var));
  return memory_get_usage() - $total_memory; 
}

$var = "Hey, what you doing?";
echo getVariableUsage($var);

Проверьте это

http://www.phpzag.com/how-much-memory-do-php-variables-use/