[英]PHP XML Memory Leak?
我們的一個常規運行腳本中存在嚴重的內存泄漏,這些腳本會快速清除服務器上的可用內存。 盡管經過了數小時的研究和實驗,但我甚至無法對其進行研究。
這是代碼:
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,但結果基本相同。 我也研究了這三個線程,但沒有找到任何有幫助的東西:
DOMDocument / Xpath在長命令行過程中泄漏內存 - 解構此類的任何方法
我希望這很簡單,我只是在俯視。
更新11/10:它不會出現內存最終被釋放。 我注意到在超過30分鍾之后,突然又出現了一大塊空地。 但顯然,最近這種情況還不夠快,以防止服務器耗盡內存並鎖定。
值得一提的是,我們在Red Hat 5.11上使用Apache 2.2.3運行PHP 5.3.15。 我們正在努力更新所有這些版本的最新版本,因此在升級路徑的某個地方,我們可能會發現這一點已經修復。 不過,在此之前做這件事會很棒。
最近遇到過和你一樣的問題。 我們需要從3gb xml文件中提取數據,並且還注意到服務器內存已達到其極限。 有幾種方法可以減少內存使用量;
你提到30分鍾后會釋放一些內存。 在30分鍾內讀取500mb xml是慢的方法。 我們使用的解決方案是將3gb xml文件分成幾個部分(aprox 200)。 我們的腳本在不到5分鍾的時間內將所需數據(大約700k記錄)寫入我們的數據庫。
我們剛剛遇到了與PHPDocxPro(使用DomDocument)類似的問題,並向他們提交了一個補丁,至少可以改善問題。 get_memory_usage()報告的內存使用量從未增加,就好像PHP根本不知道分配一樣。 通過top
或ps
觀察執行時報告的內存是我們更關心的。
// ps reports X memory usage
var $foo = (new DomDocument())->loadXML(getSomeXML());
// ps reports X + Y memory usage
var $foo = (new DomDocument())->loadXML(getSomeXML());
// ps reports X + ~2Y memory usage
var $foo = (new DomDocument())->loadXML(getSomeXML());
// ps reports X + ~3Y memory usage
在每次后續調用之前添加unset()...
// ps reports X memory usage
var $foo = (new DomDocument())->loadXML(getSomeXML());
// ps reports X + Y memory usage
unset($foo);
var $foo = (new DomDocument())->loadXML(getSomeXML());
// ps reports X + ~Y memory usage
unset($foo);
var $foo = (new DomDocument())->loadXML(getSomeXML());
// ps reports X + ~Y memory usage
我沒有深入研究擴展代碼以了解發生了什么,但我的猜測是他們在不使用PHP分配的情況下分配內存,因此,它不會被算作get_memory_usage()考慮的堆的一部分。 盡管如此,似乎確實有一些引用計數來確定是否可以釋放內存。 在后續調用之前unset($foo)
可確保擴展可以重用某些資源。 沒有它,每次運行代碼時內存使用量都會增加。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.