【问题标题】:PHP Garbage collection sucks or is it just me?PHP 垃圾收集很烂,还是只有我一个人?
【发布时间】:2011-03-23 22:11:34
【问题描述】:

我有下面的函数,我在循环中非常频繁地调用它。

当内存从 1MB 上升到 156MB 时,我等了 5 分钟。 PHP的垃圾收集器不应该在某个时候出现并减少它吗?!

是因为我将内存限制设置为 256MB 吗?

在回显点 2、3、4 处,其内存使用量相当稳定。它在第 4 点下降了半兆。但第 1 点是主内存增加的地方。可能是因为file_get_html在内存中加载了html文件。

我虽然清除和取消设置变量 $html 会解决这个问题?

function get_stuff($link, $category ){

    $html = file_get_html(trim("$link"));

    $article = $html->find('div[class=searchresultsWidget]', 0);

    echo '1 - > '.convert(memory_get_usage(true)).'<br />';  

    foreach($article->find('h4 a') as $link){

        $next_url = 'http://new.mysite.com'.$link->href;

        $font_name = trim($link->plaintext);        

        $html = file_get_html(trim("$next_url"));

        $article = $html->find('form[class=addtags]', 0);

        $font_tags = '';

        foreach($article->find('ul[class=everyone_tags] li a span') as $link){

            $font_tags .= trim($link->innertext).',';   

        }

        echo '2 - > '.convert(memory_get_usage(true)).'<br />'; 

        $font_name = mysql_real_escape_string($font_name);
        $category =  mysql_real_escape_string($category);  
        $font_tags = mysql_real_escape_string($font_tags);  

        $sql = "INSERT INTO tag_data (font_name, category, tags) VALUES ('$font_name', '$category', '$font_tags')";

        unset($font_tags);
        unset($font_name);
        unset($category); 

        $html->clear();   

        mysql_query($sql); 

        unset($sql);   

        echo '3 - > '.convert(memory_get_usage(true)).'<br />';    

} 

    unset($next_url);
    unset($link);
    $html->clear(); 
    unset($html);   
    unset($article);

    echo '4 - > '.convert(memory_get_usage(true)).'<br />';

}

如您所见,我尝试使用 unset 无力。尽管据我所知它并不好,但它不会在我调用它时立即“取消”记忆。

感谢大家对我如何减少这种向上的记忆力的帮助。

【问题讨论】:

  • 我的问题被否定了?就像来自 stackoverflow 的有用通知一样。不要只是否定代表,如果你这样做了,请在评论后跟随它。
  • 我觉得这是一个很好的问题。也许是“吸”这个词引起了这一切。赞成。
  • 在 php 中,http 请求使用的所有内存在请求结束时都会被销毁。但是 gc 用于在处理请求时管理内存。我相信这是简单的参考计数。
  • @seand 大多数情况下(即,当使用zval_ptr_dtor 时)一个变量的引用计数减少并且它达到 0,PHP 会立即释放它。这是简单的参考计数。但是 PHP 5.3 还引入了一个不时运行以捕获循环引用的垃圾收集器。是的,当请求结束时,所有的非持久内存都会被释放。
  • 你用的是什么版本的php?

标签: php memory garbage-collection


【解决方案1】:

PHP 没有合适的垃圾收集器until 5.3。它基本上只使用引用计数,这将保留循环引用直到脚本终止(例如$a =&amp; $a 是循环的)。同样,它 DID 拥有的清理代码只有在内存压力需要时才会运行。例如如果不需要新释放的内存,那么进行昂贵的清理周期是没有意义的。

从 5.3 开始,有一个适当的垃圾收集器,您可以强制它使用 gc_enable()gc_collect_cycles() 运行。

【讨论】:

    【解决方案2】:

    file_get_html() 存在已知的内存泄漏:http://simplehtmldom.sourceforge.net/manual_faq.htm#memory_leak

    解决办法是用

    $html->clear();
    

    您正在做什么,但是:您在循环内部和外部都使用了 $html。在循环中,您正在调用 $html->clear(),然后在函数的末尾附近再次调用 $html->clear()(我假设捕获了您的初始 file_get_html() 对象引用)。最后一次调用没有任何作用。您在最初的 $html = file_get_html() 调用中泄漏了内存。

    尝试在循环中使用不同的变量(也许是 $html1?),看看会发生什么。

    【讨论】:

    • 好建议,我正在尝试当我运行的这个测试结束时。您还认为从命令行运行这个 PHP 脚本会有什么不同吗?这只是出于兴趣。
    • "您正在丢失与初始 $html = file_get_html() 相关的内存。"哼?这是什么意思?
    • 这是一个很好的建议。它设法显着降低了内存增加的速度!此时它还没有超过 10MB。之前它会达到 120mb 左右!我认为这很好用,感谢 Jasonbar! :)
    • @Artefacto:我的意思是他最初的$html = file_get_html() 是泄漏内存的原因。我已更新答案以修复该声明。
    • 现在是公认的解决方案。我忙着看内存使用的回声! :)
    【解决方案3】:

    垃圾收集器的目的仅仅是捕获循环引用。

    如果没有,则一旦引用计数达到 0,变量就会立即被消除。

    我不建议您使用unset,除非在特殊情况下。改用函数并依靠变量超出范围来回收内存。

    除此之外,我们无法向您描述到底发生了什么,因为我们必须确切地知道简单的 DOM 解析器在做什么。可能有循环引用或持有引用的全局资源,但很难知道。

    请参阅 reference counting basicscollecting cycles

    【讨论】:

    • 嗯?垃圾收集是引用计数的替代方法,它具有不被循环引用愚弄的显着优势。
    • @Steven 这并不意味着这两个东西都没有在 PHP 中使用。
    • 当然可以同时使用两者,尤其是当一个系统与另一个系统交互时。例如,调用 COM 对象的 .NET 应用程序对前者有 GC,但对后者有引用计数,并且必须使两者合作。所以我要问的是 PHP 是否使用其中一个或两个(如果是,何时)?
    • @Steven 查看我在上面对 sead 的回复而发疯的评论。
    • @Seteven @Artefacto 在 PHP 中只有引用计数。
    猜你喜欢
    • 1970-01-01
    • 2010-10-12
    • 2010-12-15
    • 2010-12-16
    • 2011-08-13
    • 2020-02-08
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多