Есть ли функция в PHP (или расширение PHP), чтобы узнать, сколько памяти использует данная переменная? sizeof
просто сообщает мне количество элементов / свойств.
memory_get_usage
помогает в том, что он дает мне размер памяти, используемый всем скриптом. Есть ли способ сделать это для одной переменной?
Обратите внимание, что это находится на машине разработки, поэтому возможно загрузить расширения или инструменты отладки.
Возможно, вам нужен Профайлер памяти. Я собрал информацию об этом, но я скопировал некоторые важные вещи, которые могут вам помочь.
Как вы, вероятно, знаете, Xdebug отказался от поддержки профилирования памяти с версии 2. *. Пожалуйста, найдите строку «удаленные функции» здесь: http://www.xdebug.org/updates.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 gftftools , загрузив последний пакет здесь: 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 создаст новое окно в вашем существующем сеансе браузера, как показано ниже:
С Xhprof и Xhgui вы можете также профилировать использование процессора или просто использовать память, если это ваша проблема на данный момент. Это очень полные решения, они дают вам полный контроль, и журналы могут быть написаны как на монго, так и в файловой системе.
Подробнее см. Здесь .
Blackfire является профилировщиком PHP от SensioLabs, парней Symfony2 https://blackfire.io/
Если вы используете puphpet для настройки своей виртуальной машины, вы будете рады узнать, что она поддерживается 😉
XDEBUG2 является расширением для PHP. Xdebug позволяет записывать все вызовы функций, включая параметры и возвращаемые значения в файл в разных форматах. Существует три формата вывода. Один из них предназначен для чтения человеком, а другой – для компьютерных программ, поскольку его легче разбирать, а последний использует HTML для форматирования трассировки. Вы можете переключаться между двумя различными форматами с настройкой. Пример будет доступен здесь
forp простой, неинтрузивный, ориентированный на производство, PHP-профайлер. Некоторые функции:
измерение времени и выделенной памяти для каждой функции
использование процессора
файл и номер строки вызова функции
вывода в формате Google Trace Event
подпись функций
группировка функций
алиасы функций (полезны для анонимных функций)
DBG – полнофункциональный отладчик php, интерактивный инструмент, который помогает вам отлаживать скрипты php. Он работает на WEB-сервере производства и / или разработки и позволяет отлаживать ваши сценарии локально или удаленно из среды IDE или консоли, а ее функции:
Удаленная и локальная отладка
Явная и неявная активация
Стек вызовов, включая вызовы функций, динамические и статические вызовы методов, с их параметрами
Навигация через стек вызовов с возможностью оценки переменных в соответствующих (вложенных) местах
Ввести / Выйти / Перевернуть / Запустить в функциональность курсора
Условные точки останова
Глобальные контрольные точки
Регистрация ошибок и предупреждений
Несколько одновременных сеансов для параллельной отладки
Поддержка интерфейсов GUI и CLI
Поддерживаются сети IPv6 и IPv4
Все данные, передаваемые отладчиком, могут быть дополнительно защищены с помощью SSL
Нет прямого способа получить использование памяти одной переменной, но, как предложил Гордон, вы можете использовать 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; }
Нет, нет. Но вы можете serialize($var)
и проверить значение strlen
результата для приближения.
В ответ Тату Ульманенсу ответ:
Следует отметить, что $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 бит.
Видеть:
memory_get_usage()
– возвращает объем памяти, выделенный для PHP memory_get_peak_usage()
– возвращает пик памяти, выделенный PHP Обратите внимание, что это не даст вам использование памяти определенной переменной.
Вы могли бы также взглянуть на расширение PECL Memtrack , хотя документация немного отсутствует, если не сказать, практически несуществующей.
Вы не можете ретроспективно рассчитать точный след переменной, поскольку две переменные могут совместно использовать одно и то же выделенное пространство в памяти
Давайте попробуем поделиться памятью между двумя массивами, мы видим, что выделение второго массива стоит половину памяти первого. Когда мы снимаем первый, почти вся память все еще используется второй.
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)
с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)
с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()
нужно вызвать еще в предыдущее время и любую другую функцию.
Если вы хотите эхо, как в приведенном выше примере, ваш выходной буфер должен быть уже открыт, чтобы избежать учета памяти, необходимой для открытия выходного буфера.
Если вы хотите полагаться на функцию для вычисления необходимого пространства для хранения копии переменной, следующий код выполняет различные оптимизации:
<?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
Обратите внимание, что размер имени переменной имеет значение в выделенной памяти.
Переменная имеет базовый размер, определяемый внутренней структурой 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)
Из-за выравнивания памяти вы должны округлить до кратного 4 байта. Если переменная находится в глобальном пространстве (не внутри функции), она также выделяет еще 64 байта.
Поэтому, если вы хотите использовать один из кодов внутри этой страницы, вам нужно проверить, соответствуют ли результаты с помощью некоторых простых тестовых примеров (строк или чисел) эти данные с учетом каждого из указаний в этом сообщении (массив $ _GLOBAL, первый вызов функции, выходной буфер, …)
Вы можете выбрать вычисление разности памяти по возвращаемому значению обратного вызова. Это более элегантное решение, доступное в 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;
У меня была аналогичная проблема, и решение, которое я использовал, заключалось в том, чтобы записать переменную в файл, а затем запустить файлizeize (). Примерно так же (непроверенный код):
function getVariableSize ( $foo ) { $tmpfile = "temp-" . microtime(true) . ".txt"; file_put_contents($tmpfile, $foo); $size = filesize($tmpfile); unlink($tmpfile); return $size; }
Это решение не очень быстро, потому что оно связано с диском IO, но оно должно дать вам нечто гораздо более точное, чем трюки memory_get_usage. Это зависит от того, насколько вам необходима точность.
Никогда не пробовал, но Xdebug трассировки с xdebug.collect_assignment s могут быть достаточно.
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; }
Следующий сценарий показывает общее использование памяти одной переменной.
function getVariableUsage($var) { $total_memory = memory_get_usage(); $tmp = unserialize(serialize($var)); return memory_get_usage() - $total_memory; } $var = "Hey, what's you doing?"; echo getVariableUsage($var);
Проверь это