2010-10-25 40 views
3

我目前正在調試一個不斷運行到OutOfMemory異常的腳本。它作爲一個cronjob運行並且通常運行良好,但是當cronjob沒有運行一段時間(無論出於何種原因)時,腳本必須處理排隊的許多元素,並且會運行到OutOfMemory異常。在OutOfMemory異常上有PHP轉儲堆

從檢查代碼我無法發現問題。我相信其中一個迭代函數調用可能會泄漏內存,但我不確定哪一個在哪裏。 當出現OutOfMemory異常時,是否有一個讓PHP轉儲堆的選項?我可能會從那裏發現問題(很可能)。

+0

http://de3.php.net/manual/en/function.memory-get-peak-usage.php – teemitzitrone 2010-10-25 12:14:18

+0

我知道峯值的使用情況,這正是我腳本崩潰時的內存限制。否則我不知道這對我有什麼幫助。 – 2010-10-25 12:19:45

回答

5

雖然我無法找到「轉儲堆的異常」選項,但我確實發現get_defined_vars()這基本上是一個堆轉儲,如果從全局範圍調用。使用這個,我能夠看到有數百個(實際上有數千個)被引用的數據庫行在我的記憶中。這是由於在臭名昭着的導致泄漏的函數中沒有釋放mysql結果資源。我找到並修復了它。它現在運行良好。

+0

你是如何使用get_defined_vars()實際查明問題的?你剛剛運行一段時間的腳本,然後讓它轉儲,或者當腳本運行到內存泄漏時,是否有辦法觸發調用該函數? – 2010-12-29 23:58:31

+1

我實現了一個迭代計數器,它可以在崩潰前向我顯示迭代的大概數量,在我的情況下,它在20000到22000次迭代之間。然後我運行腳本並在第18000次迭代中使用get_defined_vars來轉儲堆。在我的情況下,然後很明顯是什麼混亂的記憶。 – 2011-01-08 11:33:12

+0

爲了讓事情更清楚一點,我爲每次迭代都將'get_defined_vars()'作爲json轉儲到一個文件中。然後通過'jq .'運行這些文件,以使它們具有相似的格式。一旦你有,你可以區分這兩個文件,並可能看到一些添加。有了這些信息,我回到了最後一個轉儲文件,並找到了添加的項目。 – 2016-02-10 06:55:01

1

那麼,最簡​​單的方法就是在腳本的可能發生錯誤的那部分周圍使用try-catch塊,並且您將不得不將堆棧轉儲到catch部分。問題可能是機器人無法響應,導致內存已滿並終止。我不知道是否有助於放棄一些變量來釋放一些內存來輸出一些數據。

編輯:爲此,使用php函數debug-backtrace。這會給你一個堆棧跟蹤。所以如果機器還在運轉,發現錯誤將很有可能。

+0

我認爲他的問題是關於如何*轉儲堆。 – 2010-10-25 12:01:57

+0

請原諒我,但我如何在抓取部分「轉儲堆」?我當然不是在談論SplHeap,而是PHP腳本的內存堆。 – 2010-10-25 12:03:14

+0

尋找記憶(http://php.net/manual-lookup.php?pattern=memory&src=)或堆(http://php.net/manual-lookup.php?pattern=heap&src=)不會產生任何有希望的結果(OT:我如何在評論中嵌入鏈接,或者我不能?) – 2010-10-25 12:16:45

0

只是不把所有對象加載到內存中,而是儘可能地讀取它們?

+0

這是腳本似乎從目測檢查代碼所做的事情。正如我所說,我懷疑有內存泄漏。也許是因爲循環引用(這是PHP 5.0),但是通過閱讀它們線來調試成千上萬行代碼可能會發現問題只是浪費時間。 – 2010-10-25 12:15:44

+0

你需要在PHP中創造一個內存泄漏,除非你只需要一個數組並放入數據(可能使用一些奇怪的聯想鍵)而不需要再次刪除它...... – joni 2010-10-25 12:37:15

+0

你的意思與創建遞歸關聯一樣有創意嗎?例如,他們會在5.3之前創建內存泄漏,因爲gc無法檢測到它們。由於我正在調試的代碼不是我的,我不知道可能會發生什麼病。 – 2010-10-25 14:24:02

0

我有很多simpleXML和內存泄漏的問題。他們很難追蹤到......花了我好幾天的時間來弄清楚那個簡單的XML引起了什麼,然後解決了它們。 據我知道你C和編程設置OOM :)

另外一個處理,PHP的顯示內存信息功能無法檢測內存泄漏,我不得不腳本吃起來〜1GB內存,但PHP的功能只報100Mb使用:)

0

這是一個'堆轉儲',因爲我可以快速寫入PHP。我採用已定義的變量和函數,然後按序列化的長度進行排序。序列化的長度是不是得到一個變量的大小100%可靠的方法,但它是相當不錯的,一般可用於確定哪些對象是你的記憶豬:

$memmap = array_map(function($var) { return strlen(serialize($var)); }, array_merge(get_defined_functions(), get_defined_vars())); arsort($memmap); var_dump($memmap);

您可能需要調整的回調函數如果你希望你的結果更加冗長,或者通過定義的變量進行遞歸,那麼有點兒。