我已经尝试用gc_collect_cycles()
强制垃圾收集,PHP仍然没有从旧的Xpath请求中获取内存.实际上,DOMXPath类的定义似乎甚至不包含析构函数?
所以我的问题是……在我已经提取了必要的数据后,有没有办法强制垃圾清理DOMXPath?在类实例上使用unset可以预测不会做任何事情.
代码没什么特别的,只是标准的Xpath东西:
//Loaded outside of loop $this->dom = new DOMDocument(); //Inside Loop $this->dom->loadHTML($output); $xpath = new DOMXPath($this->dom); $nodes = $xpath->query("//span[@class='ckass']"); //unset($this->dom) and unset($xpath) doesn't seem to have any effect
正如您在上面所看到的,我已经在循环之外保留了新DOMDocument类的实例化,尽管这似乎并没有提高性能.我甚至尝试将$xpath类实例从循环中取出并使用__constructor方法直接将DOM加载到Xpath中,内存丢失是相同的.
我找到问题的“工作”解决方案只是解决方法.基本思想是将DOMXPath :: query()返回的DOMNodeList Traversable替换为包含相同节点的另一个.
最合适的解决方法是使用DOMXPathElementsIterator
,它允许您在没有内存泄漏的情况下查询问题中的具体xpath表达式:
$nodes = new DOMXPathElementsIterator($this->dom,"//span[@class='ckass']"); foreach ($nodes as $span) { ... }
此类现在是the development version of Iterator-Garden的一部分,$nodes是所有< span>的迭代器. DOMElements.
此解决方法的缺点是xpath结果限制为SimpleXMLElement::xpath()
结果(这与DOMXPath :: query()不同),因为它在内部用于防止内存泄漏.
另一种方法是在DOMNodeList上使用DOMNodeListIterator
,就像DOMDocument::getElementsByTagname()
返回的那样.但是这些迭代很慢.
希望这是有用的,即使问题真的很老.它在类似的情况下帮助了我.
例如,如果您为同一个DOMDocument重新创建一个新的DOMXPath对象(请记住它已连接到仍然存在的DOMDocument),听起来就像是您的内存“泄漏”.你只需要使用越来越多的内存.
相反,您可以在重复使用DOMDocument对象时重复使用现有的DOMXPath对象.试一试:
//Loaded outside of loop $this->dom = new DOMDocument(); $xpath = new DOMXPath($this->dom); //Inside Loop $this->dom->loadHTML($output); $nodes = $xpath->query("//span[@class='ckass']");