How to determine the memory footprint (size) of a variable?

在 PHP (或 PHP 扩展)中是否有一个函数来查找给定变量使用了多少内存?sizeof只告诉我元素/属性的数量。

memory_get_usage helps in that it gives me the memory size used by the whole script. Is there a way to do this for a single variable?

注意,这是在开发计算机上,因此加载扩展插件或调试工具是可行的。

78920 次浏览

不,没有。但是你可以检查结果的 serialize($var)strlen得到一个近似值。

没有直接的方法可以获得单个变量的内存使用情况,但是正如 Gordon 所建议的,您可以使用 memory_get_usage。这将返回分配的内存总量,因此您可以使用变通方法并在前后度量使用情况,以获得单个变量的使用情况。这有点粗糙,但应该能行。

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

Note that this is in no way a reliable method, you can't be sure that nothing else touches memory while assigning the variable, so this should only be used as an approximation.

You can actually turn that to an function by creating a copy of the variable inside the function and measuring the memory used. Haven't tested this, but in principle, I don't see anything wrong with it:

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

从未尝试过,但使用 执行指定任务进行 Xdebug 跟踪可能就足够了。

在回答塔图•乌尔曼尼斯(Tatu Ulmanens)的问题时,他这样回答:

值得注意的是,$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位。

您可以选择在回调返回值上计算内存差。在 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;

我遇到过类似的问题,我使用的解决方案是将变量写入一个文件,然后在其上运行 filesize ()。大致如下(未测试的代码) :

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

This solution isn't terribly fast because it involves disk IO, but it should give you something much more exact than the memory_get_usage tricks. It just depends upon how much precision you require.

由于两个变量可以共享内存中相同的分配空间,因此无法回溯计算变量的确切内存占用量

Let's try to share memory between two arrays, we see that allocating the second array costs half of the memory of the first one. When we unset the first one, nearly all the memory is still used by the second one.

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)

So we can't conclude than the second array uses half the memory, as it becomes false when we unset the first one.

有关如何在 PHP 中分配内存以及如何使用内存的完整视图,我建议您阅读以下文章: PHP 数组(和值)到底有多大? (提示: 很大!)

PHP 文档中的 Reference Counting Basics还有大量关于内存使用的信息,以及对共享数据段的引用计数。

这里公开的不同解决方案对于近似来说是很好的,但是没有一个方案能够处理 PHP 内存的微妙管理。

  1. 计算新分配的空间

如果您希望在分配之后获得新分配的空间,那么您必须在分配之前和之后使用 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";

Remember that if you want to store the result of the first memory_get_usage(), the variable has to already exist before, and memory_get_usage() has to be called another previous time, and every other function also.

If you want to echo like in the above example, your output buffer has to be already opened to avoid accounting memory needed to open the output buffer.

  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. 检查你的密码!

A variable has a basic size defined by the inner C structure used in the PHP source code. This size does not fluctuate in the case of numbers. For strings, it would add the length of the 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;

如果我们不考虑变量名的初始化,我们已经知道变量使用了多少(对于数字和字符串) :

44 bytes in the case of numbers

字符串为24字节

字符串的长度(包括最后一个 NUL 字符)

(这些数字可以根据 PHP 版本而改变)

由于内存对齐,您必须四舍五入到4个字节的倍数。如果变量在全局空间中(而不是在函数中) ,它还将分配64个字节。

因此,如果你想在这个页面中使用其中一个代码,你必须检查使用一些简单测试用例(字符串或数字)的结果是否与这些数据匹配,同时考虑到这篇文章中的每一个指示($_ GLOBAL 数组,第一个函数调用,输出缓冲区,...)

下面的脚本显示了单个变量的总内存使用量。

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);

Check this out

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

你可能需要一个记忆分析器。我已经收集了所以的信息,但我已经复制了一些重要的东西,也许对你有帮助。

As you probably know, Xdebug dropped the memory profiling support since the 2.* version. Please search for the "removed functions" string here: http://www.xdebug.org/updates.php

移除了功能

删除了对内存分析的支持,因为它不能正常工作。

其他探查器选项

php-memory-profiler

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"));

最后用 KCache碾打开 callgrind.out文件

使用 Google gPerftools (推荐!)

首先,通过下载最新的软件包 https://code.google.com/p/gperftools/来安装 谷歌 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 (在我看来最适合同时分析 CPU 和内存)

使用 Xhprof许贵,您可以分析 CPU 使用情况,也可以只分析内存使用情况,如果这是您目前的问题的话。 这是一个非常完整的解决方案,它提供了完全的控制权,日志可以在 mongo 上写,也可以在文件系统中写。

For more details 看这里.

黑火

Blackfire 是由 Symfony2的伙计 https://blackfire.io/设计的 PHP 分析器

如果您使用 木偶来设置您的虚拟机,您将很高兴知道它是受支持的; -)

Xdebug 和跟踪内存使用情况

XDEBUG2 是 PHP 的扩展。Xdebug 允许您记录所有函数调用,包括参数和以不同格式返回值给文件。有三种输出格式。一个是人类可读的跟踪,另一个更适合计算机程序,因为它更容易解析,最后一个使用 HTML 格式化跟踪。您可以通过设置在两种不同的格式之间切换。这里提供的一个例子是 < a href = “ http://derickrethans.nl/xdebug-and-trace-memory-usage.html”rel = “ noReferrer”>

forp

Forp 简单、无干扰、面向生产的 PHP 分析器:

  • 测量每个功能的时间和分配的内存

  • CPU 使用率

  • file and line number of the function call

  • 输出为 Google 的跟踪事件格式

  • 函数说明函数说明

  • grouping of functions

  • 函数的别名(对匿名函数有用)

DBG

DBG 是一个功能齐全的 php 调试器,它是一个交互式工具,可以帮助您调试 php 脚本。它可以在生产和/或开发 WEB 服务器上运行,允许您从 IDE 或控制台本地或远程调试脚本,其特性如下:

  • Remote and local debugging

  • 显式和隐式激活

  • Call stack, including function calls, dynamic and static method calls, with their parameters

  • 在调用堆栈中导航,能够在相应(嵌套)位置计算变量

  • 步入/步出/步上/运行到光标功能

  • 条件断点

  • 全局断点

  • 记录错误和警告

  • 用于并行调试的多个并发会话

  • 对 GUI 和 CLI 前端的支持

  • 支持 IPv6和 IPv4网络

  • 调试器传输的所有数据都可以选择使用 SSL 进行保护