PHP SimpleXML大文件没有额外的内存使用量

时间:2013-09-21 13:50:31

标签: php memory simplexml

在每篇关于SimpleXML性能和内存使用的文章中,都提到所有已解析的内容都存储在内存中,处理大型文件会导致大量内存使用。 但最近我发现使用SimpleXML处理大型文件不会导致大量内存使用,甚至导致几乎没有内存使用。 有我的测试脚本:

<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
print "OS: " . php_uname() . "\n";
print "PHP version: " . phpversion() . "\n";

print round(memory_get_usage() / 1024 / 1024, 2) . " Mb\n";
$large_xml = '<?xml version="1.0" encoding="UTF-8"?><catalog><products>';
for ($i = 0; $i < 500000; $i++) {
    $large_xml .= "<product><id>{$i}</id><name>Product Name {$i}</name><description>Some Description {$i}</description><price>{$i}</price></product>\n";
}
$large_xml .= "</products></catalog>";
print round(memory_get_usage() / 1024 / 1024, 2) . " Mb\n";
$products_sxml = simplexml_load_string($large_xml);
print round(memory_get_usage() / 1024 / 1024, 2) . " Mb\n";
?>

我在Linux服务器上测试了这个脚本,PHP版本:5.3.8,输出是:

OS:Linux 2.6.32-5-amd64#1 SMP Mon Feb 25 00:26:11 UTC 2013 x86_64

PHP版本:5.3.8

0.6 Mb

65.98 Mb

65.98 Mb

所以我的问题是 - 是否有其他人已经注意到它以及可能对此有何解释,因为我无法在网络上的任何地方找到它的解释 - 甚至没有确认它?

3 个答案:

答案 0 :(得分:4)

PHP的内存管理功能非常复杂,准确测量特定高级代码的影响非常困难。 Julien Pauli在PHP英国会议上发表了非常好(非常技术性)的演讲,a video of which is available here

memory_get_usage可能对您说谎的原因有几个:

  • 首先,memory_get_usage采用$real_usage的可选参数,该参数区分已分配的内存量和正在使用的 - 内存管理器一次为一个块分配内存,因此它通常会从操作系统中获得比实际使用中更多的内容。由于需要更多,已经声明的内存已用完,这意味着不再需要分配内存。在这种情况下进行测试表明这与此无关。
  • 更一般地说,在运行PHP的底层C代码中有不同的分配内存的方法。由于SimpleXML的大多数工作不是在Zend Engine中完成的,而是在名为libxml2的第三方库中完成,因此内存分配将在那里完成,而不是在特定于PHP的分配例程中进行,例如,在附加时使用到PHP字符串。

我从Julien Pauli的幻灯片中获取了以下函数,该幻灯片查看Linux内核对正在运行的PHP进程的视图,并找到代表“Resident Set Size”的行 - 实际已分配的物理内存量,而不是超过要求保留的流程金额:

function heap() {
    return shell_exec(sprintf('grep "VmRSS:" /proc/%s/status', getmypid()));
}

在示例代码中添加对此(以及get_memory_usage(true))的调用,我得到以下输出,显示解析XML时“堆”内存的重要分配:

OS: Linux pink-marmalade 3.8.0-29-generic #42~precise1-Ubuntu SMP Wed Aug 14 16:19:23 UTC 2013 x86_64
PHP version: 5.3.10-1ubuntu3.8
memory_get_usage(): 0.61 Mb
memory_get_usage(true): 0.75 Mb
Heap: VmRSS:        6956 kB

memory_get_usage(): 65.99 Mb
memory_get_usage(true): 66.25 Mb
Heap: VmRSS:       74348 kB

memory_get_usage(): 65.99 Mb
memory_get_usage(true): 66.25 Mb
Heap: VmRSS:      761836 kB

答案 1 :(得分:0)

如果我执行脚本,我会得到完全相同的结果。 一种解释可能是您不使用XML对象,因此甚至不会完全解析xml字符串。 修改脚本以便将数据发送到浏览器print_r($products_sxml);时,调用后内存使用量会大大增加。 你应该明显减少xml中的产品数量。

答案 2 :(得分:0)

SimpleXML将XML树存储在外部资源中,该资源不包含在get_memory_usage函数中。