【问题标题】:PHP SimpleXML large file no extra memory usagePHP SimpleXML 大文件没有额外的内存使用
【发布时间】:2013-09-26 19:42:49
【问题描述】:

在每篇关于 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,输出是:

操作系统:Linux 2.6.32-5-amd64 #1 SMP Mon Feb 25 00:26:11 UTC 2013 x86_64

PHP版本:5.3.8

0.6 兆字节

65.98 兆字节

65.98 兆字节

所以我的问题是 - 有没有其他人注意到它,对此有什么解释,因为我在网络上的任何地方都找不到它的解释 - 甚至没有关于它的确认?

【问题讨论】:

  • 欢迎来到 SO。请考虑使您的问题尽可能简单。需要读两三遍才能明白你在问什么。
  • 问题是 - 有人可以解释为什么在使用 SimpleXML 处理大型 XML 文件时没有额外的内存使用 - 因为在每篇关于 SimpleXML 的文章中都提到大内存使用是它最大的缺点。

标签: php memory simplexml


【解决方案1】:

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

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

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

我从 Julien Pauli 的幻灯片中获取了以下函数,它查看了正在运行的 PHP 进程的 Linux 内核视图,并找到代表“驻留集大小”的行 - 实际分配的物理内存量,而不是比进程要求保留的金额:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 可以添加像foreach这样的XML处理代码($products_sxml->products->product as $product_sxml) { $product_count++; } 你会看到内存使用量没有增加。问题不是关于 XML 文件的大小,而是关于使用 SimpleXML 处理 XML 文件时没有额外的内存使用。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-20
      • 2018-12-04
      • 1970-01-01
      • 2015-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多