2011-06-14 37 views
5

tl; dr:如何在Perl httpd進程內存不足時轉儲perl堆棧跟蹤。從Perl獲取堆棧跟蹤「內存不足」錯誤

我們有一個mod_perl 2服務器,Perl 5.8.8,RHEL 5.6,Linux 2.6.18。

偶爾和不可預知的是,子httpd進程開始以驚人的速度使用所有可用內存。我們至少使用了BSD :: Resource :: setrlimit(RLIMIT_VMEM,...),這樣在關閉服務器之前,進程就會因「內存不足」而死亡。

我們不知道在代碼中發生了什麼,並且在沒有負載測試小時的情況下很難重現。

我們真正想要的是一種在進程內存耗盡之前獲得Perl堆棧跟蹤的方法,因此我們知道是什麼代碼導致了這種情況。不幸的是,「內存不足」是untrappable error

這裏是我考慮的選項,各自有各自的缺點:使用$^M emergency memory pool

1)。要求我們用-DPERL_EMERGENCY_SBRK和-Dusemymalloc重新編譯perl。

2)輸入大量的日誌語句,然後分析日誌以查看過程停止的地方。 3)編寫一個不斷掃描httpd進程池的外部腳本,如果它看到一個使用大量內存的腳本,則向它發送一個USR2信號(我們已經安排轉儲堆棧跟蹤)。

4)以某種方式持續監視自己的內存,並在內存變高但在「內存不足」錯誤之前轉儲堆棧跟蹤。

謝謝!

喬恩

+0

是否可以在[Devel :: NYTProf](http://search.cpan.org/perldoc?Devel::NYTProf)下運行該進程? – 2011-06-14 18:53:14

+0

就像我說的那樣,這個問題很少發生 - 比如在一小時的負載測試之後 - 所以如果我們運行在性能分析或重度日誌記錄的情況下,我們將不得不收集大量的數據。另外,解決方案可以在生產環境中工作,顯然,我們無法在Devel :: NYTProf下運行。 – 2011-06-14 19:07:23

回答

2

您可以嘗試使用LD_PRELOAD加載的malloc /免費的定製版本。不需要重新鏈接或重新編譯任何內容。只需將LD_PRELOAD設置爲具有與malloc相同接口的.so,並且在運行可執行文件時,將加載此預加載版本的malloc,而不是正常的系統malloc。例如,這是一種通過efence來檢測內存錯誤的常用策略。

我不認爲efence會在這裏爲你工作,因爲這是爲了檢測內存覆蓋,而不是調試內存不足(我不知道它在OOM上做什麼)。我想你可能想要檢查出failmalloc。我從來沒有使用過這個,但它聽起來像它可能做你想做的(我只是撇去頭版)。

+0

有趣。因此,理論上我可以創建一個調用malloc的malloc鉤子(http://www.gnu.org/s/hello/manual/libc/Hooks-for-Malloc.html),如果發生OOM,則可以調用 1)raise軟VMEM限制 2)再調用malloc使用相同的參數(現在應該有更高的極限成功) 3)獲得轉儲Perl的堆棧跟蹤的過程中(例如,通過將自身發送一個SIGUSR2) – 2011-06-14 21:35:38

3

您可以使用mod_backtrace進行回溯,請參閱Andy Millar's introduction。回溯是C級,讓你無論是需要

  • 一點的Perl的內部構件知識來推斷Perl的堆棧通過簡單地看回溯或
  • 運行GDB,在crashy功能設置斷點並使用mod_perl書中的gdb宏來檢查Perl堆棧和詞法變量。
+0

感謝。在C語言級別的回溯中是否有足夠的信息來確定我們在Perl堆棧中的位置,而不僅僅是我們所在的代碼行,而是調用者等等? – 2011-06-14 21:26:06

+0

喬納森:在某個地方,但這不一定很容易或公開。您可以使用call_sv/etc(請參閱perlcall)回調Perl,以便爲您的內存限制做一個Carp :: cluck。 – tsee 2011-06-15 05:12:50