【问题标题】:DOMDocument PHP Memory LeakDOMDocument PHP 内存泄漏
【发布时间】:2012-01-12 20:52:16
【问题描述】:

在 MAC 上的 MAMP 下运行 PHP 5.3.6,内存使用量每调用一次(3 到 8 次)就会增加,直到脚本因内存耗尽而死。我该如何解决这个问题?

libxml_use_internal_errors(true);
while(true){
 $dom = new DOMDocument();
 $dom->loadHTML(file_get_contents('http://www.ebay.com/'));
 unset($dom);
 echo memory_get_peak_usage(true) . '<br>'; flush();
}

【问题讨论】:

    标签: php memory-leaks domdocument


    【解决方案1】:

    使用libxml_use_internal_errors(true); 会抑制错误输出,但会构建一个连续的错误日志,并附加到每个循环中。禁用内部日志并抑制 PHP 警告,或者清除每个循环迭代的内部日志,如下所示:

    <?php
    libxml_use_internal_errors(true);
    while(true){
     $dom = new DOMDocument();
     $dom->loadHTML(file_get_contents('ebay.html'));
     unset($dom);
     libxml_use_internal_errors(false);
     libxml_use_internal_errors(true);
     echo memory_get_peak_usage(true) . "\r\n"; flush();
    }
    ?>
    

    【讨论】:

    • 非常感谢。我为此搜索过很多次,但从未想过要查看使用 libxml_use_internal_errors(true) 的含义
    • 我怀疑这也是答案:*.com/questions/8188729/…
    • 随意在其他答案和/或链接中交叉发布并传播爱。 @FrancisAvila 谢谢,很好发现:)
    • 如果可以的话+100!哥们,你是救命恩人。一直以来,我都认为这是 DOMDocument 的错误,并且一直在修改它,是时候重构了。 =)
    • 是啊!我被阻止试图知道我的内存泄漏来自哪里,而你指出了正确的方向。非常感谢!
    【解决方案2】:

    根据@Tak 的回答和@FrancisAvila 的评论,我发现这个sn-p 更适合我:

    while (true)
    {
        $dom = new DOMDocument();
    
        if (libxml_use_internal_errors(true) === true) // previous setting was true?
        {
            libxml_clear_errors();
        }
    
        $dom->loadHTML(file_get_contents('ebay.html'));
    }
    
    print_r(libxml_get_errors()); // errors from the last iteration are accessible
    

    这有额外的好处 1) 如果您需要通过 libxml_get_errors() 访问它们,则不会丢弃 last 解析的错误,以及 2) 仅在必要时调用 libxml_clear_errors(),因为libxml_use_internal_errors() 返回上一个设置状态。

    【讨论】:

      【解决方案3】:

      您可以尝试强制垃圾收集器使用gc_collect_cycles() 运行,否则您将不走运。 PHP 没有公开任何东西来控制其内部内存使用,更不用说插件库使用的内存了。

      【讨论】:

      • 不幸的是,在脚本开始时使用gc_enable(),在每个循环结束时使用gc_collect_cycles(),内存不断消耗,返回0。
      【解决方案4】:

      在本地测试您的脚本会产生相同的结果。但是,将 file_get_contents() 更改为本地 HTML 文件会产生一致的内存使用情况。可能是 ebay.com 的输出在每次调用 X 时都会发生变化。

      【讨论】:

      • 将 eBay 主页保存到本地 html 文件,然后使用它会产生相同的内存膨胀。包含的代码是我的问题代码的简化 - 它实际上是从本地缓存加载内容。
      • 啊哈,找到了解决方案 - 将在单独的答案中发布