【发布时间】:2016-02-10 08:20:06
【问题描述】:
在我们定期运行的脚本之一中存在严重的内存泄漏,该脚本会迅速清除服务器上的可用内存。尽管进行了许多小时的研究和实验,但我什至无法对此有所了解。
代码如下:
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 的内存使用量。
但真正的问题是,PHP 显示的内存使用量只是脚本占用的总内存的一小部分。直接从服务器上的命令行使用free -m,我们将使用的内存从 3,295 MB 变为 5,226 MB -- 并且它永远不会降级。每次运行此脚本时,我们都会丢失 2 GB 的内存,我完全不知道为什么或如何修复它。
我尝试改用 SimpleXML,但结果基本相同。我也研究了这三个线程,但没有找到任何帮助:
XML xpath search and array looping with php, memory issue
我希望这是一件容易被我忽略的事情。
11/10 更新:确实似乎内存最终被释放了。我注意到,30多分钟后,突然又腾出了一大块。但显然,最近这还不够快,无法防止服务器内存不足和锁定。
不管怎样,我们在 Red Hat 5.11 上运行 PHP 5.3.15 和 Apache 2.2.3。我们正在努力更新到所有这些的最新版本,所以沿着升级路径的某个地方,我们可能会发现这个问题已修复。不过,在那之前做这件事会很棒。
【问题讨论】:
-
试试看
$oNodes在你之前有多少引用unsetphp.net/manual/en/features.gc.refcounting-basics.php -
假设 apache,请记住每个子节点都有自己独立的内存池,如果您正在并行处理“巨大”xml 文档,则子节点之间不会共享任何 dom 基础结构。您可以将 max_requests_per_child (无论设置如何)设置为低,因此 apache 会更频繁地核对/重新启动子级,这将释放一些持有的内存。
-
@Machavity:我们没有安装 Xdebug。有没有办法在没有它的情况下计算引用?
-
@Marc B:我不确定在这种情况下您所说的“孩子”是什么意思。对不起。在这种情况下,此脚本将运行一次。它不会同时受到两个不同进程的影响。
-
php 不会因为您取消设置变量而运行其垃圾收集器。 GC 运行在计算上非常昂贵,因此 PHP 在必须运行它之前不会运行它,例如记忆越来越紧。所以 memory_get_usage() 并不是一个真正有效的测试。
标签: php dom memory xpath memory-leaks