如何确定变量的内存占用(大小)?

时间:2010-02-03 14:37:09

标签: php memory

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

memory_get_usage有助于它为我提供整个脚本使用的内存大小。有没有办法为单个变量执行此操作?

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

11 个答案:

答案 0 :(得分:91)

没有直接的方法来获取单个变量的内存使用情况,但正如Gordon建议的那样,您可以使用memory_get_usage。这将返回分配的内存总量,因此您可以使用变通方法并测量前后使用情况以获取单个变量的使用情况。这有点hacky,但它应该工作。

$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;
}

答案 1 :(得分:40)

您可能需要Memory Profiler。我收集了信息,但我已经复制了一些可能对你有帮助的重要事情。

正如您可能知道的那样,Xdebug从2. *版本开始删除了内存分析支持。请在此处搜索“已删除的功能”字符串:http://www.xdebug.org/updates.php

  

删除了功能

     

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

其他Profiler选项

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

然后打开终端并启动:

pprof --web /tmp/profile.heap

pprof 将在您现有的浏览器会话中创建一个新窗口,其内容如下所示:

PHP memory profiling with memprof and gperftools

Xhprof + Xhgui(我认为最好用cpu和内存来分析)

使用 Xhprof Xhgui ,您可以分析cpu使用情况,也可以只查看内存使用情况,如果这是您目前的问题。 这是一个非常完整的解决方案,它可以让您完全控制,并且可以在mongo或文件系统中编写日志。

有关详情see here

Blackfire

Blackfire是SensioLabs的PHP探查器,Symfony2人https://blackfire.io/

如果您使用puphpet设置虚拟机,您会很高兴知道它受到支持; - )

Xdebug和跟踪内存使用情况

XDEBUG2是PHP的扩展。 Xdebug允许您记录所有函数调用,包括参数和返回值到不同格式的文件。有三种输出格式。一个是人类可读的跟踪,另一个更适合计算机程序,因为它更容易解析,最后一个使用HTML格式化跟踪。您可以使用该设置在两种不同格式之间切换。一个例子是available here

forp

forp简单,非侵入式,面向生产的PHP分析器。一些功能是:

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

  • CPU使用率

  • 函数调用的文件和行号

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

  • 功能标题

  • 分组职能

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

DBG

DBG是一个功能齐全的php调试器,一个可以帮助您调试PHP脚本的交互式工具。它适用于生产和/或开发WEB服务器,允许您从IDE或控制台本地或远程调试脚本,其功能包括:

  • 远程和本地调试

  • 显式和隐式激活

  • 调用堆栈,包括函数调用,动态和静态方法调用及其参数

  • 通过调用堆栈导航,能够评估相应(嵌套)位置的变量

  • 介入/退出/跳过/运行到光标功能

  • 条件断点

  • 全球断点

  • 记录错误和警告

  • 并行调试的多个同时会话

  • 支持GUI和CLI前端

  • 支持IPv6和IPv4网络

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

答案 2 :(得分:23)

不,没有。但您可以serialize($var)并检查结果的strlen以获得近似值。

答案 3 :(得分:20)

回答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位。

答案 4 :(得分:4)

请参阅:

请注意,这不会为您提供特定变量的内存使用情况。但是您可以在分配变量之前和之后调用这些函数,然后比较这些值。这应该让你了解所使用的内存。

您还可以查看PECL extension Memtrack,但文档有点缺乏,如果不是说,几乎不存在。

答案 5 :(得分:3)

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

答案 6 :(得分:3)

您无法回顾性地计算变量的确切足迹,因为两个变量可以在内存中共享相同的分配空间

让我们尝试在两个阵列之间共享内存,我们看到分配第二个阵列的成本是第一个阵列的一半。当我们取消第一个时,几乎所有的内存仍被第二个使用。

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中分配内存以及如何使用内存的完整视图,建议您阅读以下文章:How big are PHP arrays (and values) really? (Hint: BIG!)

PHP文档中的Reference Counting Basics也有很多关于内存使用的信息,引用计入共享数据段。

此处公开的不同解决方案适用于近似值,但没有一个可以处理PHP内存的细微管理。

  1. 计算新分配的空间
  2. 如果你想要在分配之后新分配的空间,那么你必须在分配之前和之后使用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()必须再次调用,而其他所有函数也必须调用。< / p>

    如果你想在上面的例子中回声,你的输出缓冲区必须已经打开,以避免打开输出缓冲区所需的记帐内存。

    1. 计算所需空间
    2. 如果您希望依靠函数来计算存储变量副本所需的空间,则以下代码会处理不同的优化:

      <?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. 检查您的代码!!
      2. 变量的基本大小由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数组,第一个函数调用,输出缓冲区,...)

答案 7 :(得分:2)

我遇到了类似的问题,我使用的解决方案是将变量写入文件,然后对其运行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技巧更准确。这取决于你需要多少精度。

答案 8 :(得分:1)

从未尝试过,但使用xdebug.collect_assignment的Xdebug跟踪可能就足够了。

答案 9 :(得分:1)

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

答案 10 :(得分:0)

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

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

检查出来

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