如何确定一个variables的内存占用(大小)?
PHP(或PHP扩展)中是否有函数来查找给定variables使用多less内存? sizeof
只是告诉我元素/属性的数量。
memory_get_usage
有助于提供整个脚本使用的内存大小。 有没有办法做到这一点的单个variables?
请注意,这是在开发机器上,所以加载扩展或debugging工具是可行的。
你可能需要一个内存分析器。 我已经收集了所有的信息,但我已经复制了一些可能帮助你的重要事情。
正如你可能知道的那样,自从2. *版本以来,Xdebug放弃了内存分析支持。 请在这里search“删除的函数”string: http : //www.xdebug.org/updates.php
删除了function
由于无法正常工作,删除了对内存分析的支持。
其他分析器选项
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"));
最后用KCachegrind打开callgrind.out
文件
使用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"));
然后打开你的terminal并启动:
pprof --web /tmp/profile.heap
pprof将在您现有的浏览器会话中创build一个新窗口,如下所示:
Xhprof + Xhgui(在我看来最好的configurationCPU和内存)
有了Xhprof和Xhgui,你可以分析CPU使用情况,或者只是内存使用情况,如果这是你的问题。 这是一个非常完整的解决scheme,它可以让你完全控制,日志可以写在mongo或文件系统中。
欲了解更多详情请参阅这里
黑火
Blackfire是SensioLabs的一个PHP profiler,Symfony2的家伙https://blackfire.io/
如果你使用puphpet来设置你的虚拟机,你会很高兴知道它的支持;-)
Xdebug和跟踪内存使用情况
XDEBUG2是PHP的扩展。 Xdebug允许你logging所有的函数调用,包括参数和返回值到不同格式的文件。有三种输出格式。 一个意思是人类可读的踪迹,另一个更适合计算机程序,因为它更容易parsing,最后一个使用HTML格式化跟踪。 您可以使用设置在两种不同的格式之间切换。 这里有一个例子
forp
福特简单,非侵入性,生产型,PHP分析器。 一些function是:
-
测量每个function的时间和分配的内存
-
CPU使用率
-
文件和函数调用的行号
-
输出为Google的跟踪事件格式
-
function标题
-
function分组
-
函数的别名(对匿名函数有用)
DBG
DBG是一个全function的PHPdebugging器,一个交互式工具,可以帮助您debuggingPHP脚本。 它可以在生产和/或开发WEB服务器上运行,并允许您从IDE或控制台本地或远程debugging脚本,其function如下:
-
远程和本地debugging
-
显式和隐式激活
-
调用堆栈,包括函数调用,dynamic和静态方法调用,以及它们的参数
-
通过调用堆栈导航,能够评估相应(嵌套)位置的variables
-
步入/步出/跳过/运行到游标function
-
条件断点
-
全局断点
-
logging错误和警告
-
多个同步会话进行并行debugging
-
支持GUI和CLI前端
-
支持IPv6和IPv4networking
-
debugging器传输的所有数据都可以使用SSL进行select性保护
有没有直接的方法来获取单个variables的内存使用情况,但正如Gordon所build议的那样,您可以使用memory_get_usage
。 这将返回分配的内存总量,因此您可以使用一种解决方法并衡量前后的使用情况,以获取单个variables的使用情况。 这有点冒失,但它应该工作。
$start_memory = memory_get_usage(); $foo = "Some variable"; echo memory_get_usage() - $start_memory;
请注意,这绝不是一个可靠的方法,您不能确定在分配variables时没有其他东西触及内存,所以这只能用作近似值。
您可以通过在函数内部创build一个variables的副本并测量所使用的内存来将其转换为函数。 没有testing过这个,但是原则上我看不出有什么问题:
function sizeofvar($var) { $start_memory = memory_get_usage(); $tmp = unserialize(serialize($var)); return memory_get_usage() - $start_memory; }
不,那里没有。 但是,你可以serialize($var)
并检查结果的大小,以近似值。
回答Tatu Ulmanens回答:
需要注意的是, $start_memory
本身会占用内存( PHP_INT_SIZE * 8
)。
所以整个function应该变成:
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分配的内存的峰值
请注意,这不会给你一个特定variables的内存使用情况。
你也可以看一下PECL的扩展Memtrack ,虽然文档有点缺乏,如果不是说,几乎不存在。
由于两个variables可以在内存中共享相同的已分配空间,因此无法追溯计算variables的确切空间
让我们试着在两个数组之间共享内存,我们看到分配第二个数组的成本是第一个数组的一半。 当我们解除第一个时,几乎所有的内存仍然被第二个使用。
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中分配内存以及为何使用内存的完整视图,我build议您阅读以下文章: PHP数组(和值)有多大? (提示:大!)
PHP文档中的引用计数基础知识还包含大量有关内存使用情况的信息,并且引用计入共享数据段。
这里公开的不同的解决scheme是很好的近似,但没有人可以处理微妙的PHP内存pipe理。
- 计算新分配的空间
如果你想在赋值之后新分配的空间,那么你必须在分配之前和之后使用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()
的结果,则该variables必须先前已经存在,而memory_get_usage()
必须先前被调用,而其他函数也必须先前被调用。
如果要像上面的例子那样回显,那么必须已经打开输出缓冲区,以避免打开输出缓冲区所需的记帐内存。
- 计算所需空间
如果你想依靠一个函数来计算所需的空间来存储一个variables的副本,下面的代码负责不同的优化:
<?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
请注意,variables名称的大小在分配的内存中很重要。
- 检查你的代码!
一个variables具有由PHP源代码中使用的内部C结构定义的基本大小。 这个大小在数字的情况下不会波动。 对于string,它会添加string的长度。
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;
如果我们不考虑variables名的初始化,我们已经知道一个variables使用多less(在数字和string的情况下):
在数字的情况下是44个字节
&加; string的情况下为24个字节
&加; string的长度(包括最后的NUL字符)
(这些数字可以根据PHP版本而改变)
由于内存alignment,您必须四舍五入到四个字节的倍数。 如果variables在全局空间中(不在函数内部),它也会分配64个字节。
所以,如果你想使用这个页面中的一个代码,你必须检查使用一些简单的testing用例(string或数字)的结果是否匹配这些数据,考虑到这个post中的每一个指示($ _GLOBAL数组,第一个函数调用,输出缓冲区…)
您可以select计算callback返回值的内存差异。 这是PHP 5.3+中更优雅的解决scheme。
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;
我有一个类似的问题,我使用的解决scheme是将variables写入文件,然后运行filesize()。 粗略的像这样(未经testing的代码):
function getVariableSize ( $foo ) { $tmpfile = "temp-" . microtime(true) . ".txt"; file_put_contents($tmpfile, $foo); $size = filesize($tmpfile); unlink($tmpfile); return $size; }
这个解决scheme不是非常快,因为它涉及到磁盘IO,但它应该给你比memory_get_usage技巧更精确的东西。 这取决于你需要多less精度。
从来没有尝试过,但Xdebug跟踪xdebug.collect_assignment可能就足够了。
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; }
以下脚本显示单个variables的总内存使用情况。
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);
看一下这个