2015-11-09 60 views
4

我们的一个定期运行的脚本中存在严重的内存泄漏,这些脚本会迅速清除服务器上的可用内存。尽管进行了许多小时的研究和实验,但我甚至无法在其中做出改变。PHP XML内存泄漏?

下面是代码:

echo '1:'.memory_get_usage()."\n"; 
ini_set('memory_limit', '1G'); 
    echo '2:'.memory_get_usage()."\n"; 

$oXML = new DOMDocument(); 
    echo '3:'.memory_get_usage()."\n"; 
$oXML->load('feed.xml'); # 556 MB file 
    echo '4:'.memory_get_usage()."\n"; 

$xpath = new DOMXPath($oXML); 
    echo '5:'.memory_get_usage()."\n"; 
$oNodes = $xpath->query('//feed/item'); # 270,401 items 
    echo '6:'.memory_get_usage()."\n"; 

unset($xpath); 
    echo '7:'.memory_get_usage()."\n"; 
unset($oNodes); 
    echo '8:'.memory_get_usage()."\n"; 
unset($oXML); 
    echo '9:'.memory_get_usage()."\n"; 

这里是输出:

1:679016 
2:679320 
3:680128 
4:680568 
5:681304 
6:150852408 
7:150851840 
8:34169968 
9:34169448 

正如你可以看到,当我们使用XPath的节点加载到一个对象,内存使用量从跳跃681,304至150,852,408。我并不担心这一点。

我的问题是,即使在销毁$ oNodes对象后,我们仍然停留在内存使用情况34,169,968。

real问题是PHP显示的内存使用量是脚本占用内存总量的一小部分。直接从服务器上的命令行使用free -m,我们从3,295 MB内存使用到5,226 MB - ,它永远不会回落到。每次脚本运行时,我们都会丢失2 GB的内存,并且我完全丧失了为什么或者如何修复它。

我尝试使用SimpleXML代替,但结果基本相同。我也研究了这三个线程,但没有发现他们什么,帮助:

XML xpath search and array looping with php, memory issue

DOMDocument/Xpath leaking memory during long command line process - any way to deconstruct this class

DOMDocument PHP Memory Leak

我希望这是一件简单的说,我只是俯瞰。

UPDATE 11/10:它确实显示内存最终被释放。我注意到在超过30分钟后,突然一个大块再次释放。不过,显然,最近这样的速度还不够快,以防止服务器内存不足和锁定。

而且值得一提的是,我们在Red Hat 5.11上使用Apache 2.2.3运行PHP 5.3.15。我们正在努力更新所有这些更新的最新版本,因此,在升级途径的某处,我们可能会发现这个问题已得到解决。不过,在那之前做这件事真是太棒了。

+0

试着看看有多少引用'$ oNodes'在你'unset'之前假设apache http://php.net/manual/en/features.gc.refcounting-basics.php – Machavity

+0

,记得每个孩子都有自己的单独的内存池,如果您正在并行处理“巨大”的xml文档,则dom基础架构不会在子项之间共享。你可以设置max_requests_per_child(无论设置是什么)低,所以apache会更频繁地释放/重启孩子,这会释放一些持有的内存。 –

+0

@Machavity:我们没有安装Xdebug。有没有办法在没有它的情况下对参考进行计数? –

回答

0

最近经历了一个和你一样的问题。我们需要从3gb xml文件中提取数据,并且还注意到服务器内存达到了极限。有几种方法可以减少内存使用量;

  • 而不是使用导致大量内存使用的xpath使用(例如)file_get_contents。然后通过正则表达式进行搜索以找到所需数据
  • 将xml分成更小的片段。基本上它重新创建xml文件,但是您可以处理文件的最大大小(因此可以处理内存)

您提到30分钟后释放了一些内存。在30分钟内读取500mb xml是减速的方法。我们使用的解决方案是将3gb xml文件分成几块(aprox 200)。我们的脚本在不到5分钟内将所需数据(大约700k条记录)写入我们的数据库。