簡體   English   中英

PHP XML內存泄漏?

[英]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,但結果基本相同。 我也研究了這三個線程,但沒有找到任何有幫助的東西:

XML xpath搜索和數組循環與PHP,內存問題

DOMDocument / Xpath在長命令行過程中泄漏內存 - 解構此類的任何方法

DOMDocument PHP內存泄漏

我希望這很簡單,我只是在俯視。

更新11/10:它不會出現內存最終被釋放。 我注意到在超過30分鍾之后,突然又出現了一大塊空地。 但顯然,最近這種情況還不夠快,以防止服務器耗盡內存並鎖定。

值得一提的是,我們在Red Hat 5.11上使用Apache 2.2.3運行PHP 5.3.15。 我們正在努力更新所有這些版本的最新版本,因此在升級路徑的某個地方,我們可能會發現這一點已經修復。 不過,在此之前做這件事會很棒。

最近遇到過和你一樣的問題。 我們需要從3gb xml文件中提取數據,並且還注意到服務器內存已達到其極限。 有幾種方法可以減少內存使用量;

  • 而不是使用導致大量內存使用的xpath(例如)file_get_contents。 然后通過正則表達式進行搜索以查找所需數據
  • 將xml拆分成更小的部分。 基本上它重新發明了xml文件,但你可以處理文件的最大大小(因此內存)

你提到30分鍾后會釋放一些內存。 在30分鍾內讀取500mb xml是慢的方法。 我們使用的解決方案是將3gb xml文件分成幾個部分(aprox 200)。 我們的腳本在不到5分鍾的時間內將所需數據(大約700k記錄)寫入我們的數據庫。

我們剛剛遇到了與PHPDocxPro(使用DomDocument)類似的問題,並向他們提交了一個補丁,至少可以改善問題。 get_memory_usage()報告的內存使用量從未增加,就好像PHP根本不知道分配一樣。 通過topps觀察執行時報告的內存是我們更關心的。

// 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM