我有一个下面的函数,我经常在循环中调用它。
随着内存从1MB上升到156MB,我等了5分钟。 PHP的garabage收集器不应该在某个时候出现并减少它吗?!
是因为我将内存限制设置为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 />';
}
正如你所看到的,我试图无力地利用未设置的东西。虽然它并不好,因为我理解它不会在我打电话时“取消”记忆。
感谢大家帮助我如何减少记忆力的上升。
答案 0 :(得分:8)
file_get_html()有一个已知的内存泄漏:http://simplehtmldom.sourceforge.net/manual_faq.htm#memory_leak
解决方案是使用
$html->clear();
你在做什么,但是:你在循环的内部和外部使用$ html。在循环内部,您调用$ html-&gt; clear(),然后在函数结束时再接近$ html-&gt; clear()(我假设抓住您的初始file_get_html()对象引用)。最后一次通话没有做任何事情。你正在通过最初的$html = file_get_html()
电话泄漏记忆。
尝试在循环中使用另一个变量($ html1,可能?),看看会发生什么。
答案 1 :(得分:3)
垃圾收集器的目的仅仅是捕获循环引用。
如果没有,则一旦参考计数达到0,变量就会立即消除。
除特殊情况外,我不建议您使用unset
。使用函数代替并依赖变量超出范围以回收内存。
除此之外,我们无法向您描述究竟是什么,因为我们必须确切地知道简单的DOM解析器正在做什么。可能存在循环引用或持有引用的全局资源,但是很难知道。
答案 2 :(得分:2)
PHP没有合适的垃圾收集器until 5.3。它基本上只使用引用计数,这将留下循环引用,直到脚本终止(例如$a =& $a
为循环)。同样,DID所具有的清理代码只有在内存压力要求时才会运行。例如如果不需要新释放的内存,则无需进行昂贵的清理周期。
从5.3开始,有一个合适的垃圾收集器,您可以强制它与gc_enable()
和gc_collect_cycles()
一起运行。