内存使用的PHP进程

概要


简短的推荐(来自更多的数据资料,见答案)

为了避免内存泄漏,您可以:

  1. 当它们变得无用时立即取消设置variables
  2. 你可以使用xdebug来查看内存功耗的详细报告,并找出内存泄漏
  3. 你可以设置memory_limit (例如5Mb)来避免虚拟内存分配

对于什么PHP可以使用内存,除了库和variables? 我监视内存,由variables和〜3Mb与这个代码使用:

$vars = array_keys(get_defined_vars()); $cnt_vars = count($vars); $allsize = 0; for ($j = 0; $j < $cnt_vars; $j++) { try { $size = @serialize($$vars[$j]); $size = strlen($size); } catch(Exception $e){ $str = json_encode($$vars[$j]); $str = str_replace(array('{"','"}','":"','":'), '', $str); $size = strlen($str); } $vars[$j] = array( 'size' => $size, 'name' => $vars[$j] ); $allsize += $size; } 

和库需要〜18Mb(libcurl等)所以总共21 MB,但是

pmap -x(进程)显示,总内存消耗是kB:314028 RSS:74704脏:59672

所以,实际消费总量是〜74Mb。 另外我看到一些大的块与[anon]映射在我的pmap为什么PHP使用这个块?

php版本: 5.5.9-1ubuntu4.14 php扩展:

 root@webdep:~# php -m [PHP Modules] bcmath bz2 calendar Core ctype curl date dba dom ereg exif fileinfo filter ftp gd gettext hash iconv json libxml mbstring mcrypt mhash openssl pcntl pcre PDO pdo_pgsql pgsql Phar posix readline Reflection session shmop SimpleXML soap sockets SPL standard sysvmsg sysvsem sysvshm tokenizer wddx xml xmlreader xmlwriter Zend OPcache zip zlib [Zend Modules] Zend OPcache 

注意:这不是一个完全的答案,而是OP所要求的信息,但是注释字段对于这个来说太短了……这些更多的工具是如何调试这类问题的。

Xdebug的文档非常全面 ,他们应该通过将文档复制到这里来告诉我如何使用它。 你给的脚本有点模糊,所以我没有自己做跟踪,但它会给你逐行的内存使用率的差异。

基本上将xdebug.show_mem_delta设置为1并启用Xdebug来生成函数跟踪,然后在文本编辑器中打开,以查看泄漏内存的部分。

然后,您可以比较初始(或中间位置)总内存,以查看它与实际内存使用情况的差异。

 TRACE START [2007-05-06 14:37:26] 0.0003 114112 +114112 -> {main}() ../trace.php:0 

这里的总内存将是114112

如果差别真的很大,可以使用shell_exec()来获得所有行之间的实际内存使用情况,然后输出结果,然后将输出结果与Xdebug的内存输出进行比较,以查看差异发生的位置。

如果区别在脚本的第一行,罪魁祸首可能是PHP的扩展。 如果有任何可疑的扩展名,请参阅php -m

PHP与编译为单个二进制文件的C或CPP代码不同。 所有的脚本都在Zend虚拟机内执行。 而且大部分的内存都被虚拟机本身消耗掉了。 这包括加载的扩展使用的内存PHP进程使用的共享库(.so文件)和任何其他共享资源。

我不记得确切的源代码,但是我读到的地方是,PHP内部消耗了近70%的CPU周期,而只有30%的代码到达你的代码(如果我在这里错了,请纠正我)。 这与内存消耗没有直接关系,但应该介绍一下PHP的工作原理。

关于匿名块,我在另一个SO答案中找到了一些细节。 答案是关于Java,但也应该适用于PHP。

匿名块是通过malloc或mmap分配的“大”块 – 请参阅联机帮助页。 因此,它们与Java堆没有任何关系(除了整个堆应该存储在这个块中的事实之外)。

我会建议禁用一些扩展。 这应该可以节省一些未使用的内存。

首先创建一个数组,调查正在使用的内存

 $startMemory = memory_get_usage(); $array = range(1, 100000); echo memory_get_usage() - $startMemory, ' bytes'; 

一个整数是8 bytes (在一个64 bit unix machine ,使用long型),这里是100000 integers ,所以你显然需要800000 bytes 。 这就像0.76 MB

这个数组给出了14649024 bytes 。 这是13.97 MB比估计的多十八倍

下面是所涉及的不同组件的内存使用情况的简要总结:

                              |  64位|  32位
 -------------------------------------------------- - 
 zval |  24字节|  16个字节
 +循环GC信息|  8个字节|  4字节
 +分配标题|  16字节|  8个字节
 ================================================== =
 zval(value)total |  48字节|  28个字节
 ================================================== =
桶|  72字节|  36个字节
 +分配标题|  16字节|  8个字节
 +指针|  8个字节|  4字节
 ================================================== =
桶(数组元素)total |  96字节|  48个字节
 ================================================== =
总计|  144字节|  76字节

同样,对于大的静态数组,如果我像这样调用:

 $startMemory = memory_get_usage(); $array = new SplFixedArray(100000); for ($i = 0; $i < 100000; ++$i) { $array[$i] = $i; } echo memory_get_usage() - $startMemory, ' bytes'; 

这将导致5600640 bytes

这是每个元素56 bytes ,因此比正常数组使用的每个元素的144 bytes少得多。 这是因为固定阵列不需要桶结构。 所以每个元素只需要一个zval (48 bytes)和一个pointer (8 bytes) ,给出观察到的56 bytes

希望这会有所帮助。

你看到的数字没有什么错,你不应该把它们合并起来,这只是“三倍”,你看到分开列出的库的不同部分(只读,可执行,可写),你的编号是正确的。