Answers:
您可能需要一个内存探查器。我已经收集了一些信息,但是我复制了一些可能对您有所帮助的重要信息。
您可能知道,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 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将在您现有的浏览器会话中创建一个新窗口,如下所示:
使用Xhprof和Xhgui,您还可以分析cpu的使用情况,或者仅分析内存使用情况(如果这是当前的问题)。这是一个非常完整的解决方案,它使您可以完全控制,并且日志可以写在mongo或文件系统中。
有关更多详细信息,请参见此处。
Blackfire是由Symfony2伙计SensioLabs(https://blackfire.io/)进行的PHP分析器
如果您使用puphpet来设置您的虚拟机,您将很高兴知道它的支持;-)
XDEBUG2是PHP的扩展。Xdebug允许您记录所有函数调用,包括参数和以不同格式返回值到文件的格式。共有三种输出格式。一个被定义为人类可读的跟踪,另一个则更易于解析,更适合于计算机程序,而最后一个则使用HTML格式化跟踪。您可以使用该设置在两种不同格式之间切换。这里有一个例子
forp简单,非侵入式,面向生产的PHP分析器。一些功能是:
时间测量和每个功能分配的内存
CPU使用率
函数调用的文件和行号
输出为Google的跟踪事件格式
功能说明
功能分组
函数别名(对匿名函数有用)
DBG是一个功能齐全的php调试器,它是一个交互式工具,可以帮助您调试php脚本。它可以在生产和/或开发的WEB服务器上运行,并允许您从IDE或控制台本地或远程调试脚本,其功能包括:
远程和本地调试
显式和隐式激活
调用堆栈,包括函数调用,动态和静态方法调用及其参数
在调用堆栈中导航并能够评估相应(嵌套)位置的变量
进入/退出/跳过/运行到光标功能
条件断点
全局断点
记录错误和警告
多个同时会话以进行并行调试
支持GUI和CLI前端
支持IPv6和IPv4网络
调试器传输的所有数据都可以选择受SSL保护
没有直接的方法来获取单个变量的内存使用情况,但是正如Gordon建议的那样,您可以使用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;
}
$tmp = $var
将创建一个浅表副本。在修改$ tmp之前,这不会分配更多的内存。
$tmp = unserialize(serialize($var))
?这将结合上面的Aistina方法。
$var
已经是传递给函数的内容的浅表副本或引用,因此您不需要$tmp
,但可以将其重新分配给$var
。这会将内部参考从保存$tmp
到$var
。
$tmp
从$var
?
不,那里没有。但是您可以serialize($var)
检查strlen
结果的近似值。
strlen(serialize(array(1,2,3)))
是30
在回答塔图·乌尔曼尼斯时,回答:
请注意,它$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位。
* 8
吗?谢谢!
PHP_INT_SIZE
字节,而是PHP_INT_SIZE*8
。:您可以尝试通过调用这个函数,它应该返回0function sizeofvar() { $start_memory = memory_get_usage(); return memory_get_usage() - $start_memory - PHP_INT_SIZE*8; }
8
似乎不是恒定的。在您的开发系统(PHP 5.6.19)上执行注释功能后,它返回-16
。同样,有趣的是,从中php -a
,调用函数的两行给出了各种不同的值。
看到:
memory_get_usage()
—返回分配给PHP的内存量memory_get_peak_usage()
—返回PHP分配的内存峰值请注意,尽管如此,这不会为您提供特定变量的内存使用量。但是您可以在分配变量之前和之后对这些函数进行调用,然后比较这些值。那应该使您对所使用的内存有一个了解。
您也可以看看PECL扩展Memtrack,尽管该文档有点缺乏(如果不是说的话),实际上根本不存在。
您可以选择计算回调返回值的内存差异。这是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;
您无法追溯地计算变量的确切占用空间,因为两个变量可以共享内存中的相同分配空间
让我们尝试在两个数组之间共享内存,我们看到分配第二个数组的开销是第一个数组的一半。当我们取消第一个设置时,第二个几乎仍使用所有内存。
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";
请记住,如果要存储first的结果,则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
请注意,变量名称的大小在分配的内存中很重要。
变量的基本大小由PHP源代码中使用的内部C结构定义。在数字的情况下,此大小不会波动。对于字符串,它将添加字符串的长度。
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数组,第一个函数调用,输出缓冲区,...)
zvalue
,is_ref
和写入时复制的内部。谢谢。
我有一个类似的问题,我使用的解决方案是将变量写入文件,然后在其上运行filesize()。大致像这样(未经测试的代码):
function getVariableSize ( $foo )
{
$tmpfile = "temp-" . microtime(true) . ".txt";
file_put_contents($tmpfile, $foo);
$size = filesize($tmpfile);
unlink($tmpfile);
return $size;
}
该解决方案并不是很快,因为它涉及磁盘IO,但是它应该给您的东西比memory_get_usage技巧更精确。这仅取决于您需要多少精度。
strlen
会更容易。
从未尝试过,但是使用xdebug.collect_assignment进行 Xdebug跟踪可能就足够了。
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);
看一下这个