内存不足:杀死进程或牺牲孩子
現在是早上6點。 我清醒地總結了導致我太早醒來的電話的事件序列。 這些故事開始時,我的電話警報響了。 困倦而脾氣暴躁的我檢查了電話,看我是否真的瘋了以至于無法在凌晨5點設置喚醒警報。 不,這是我們的監視系統,表明Plumbr服務之一已關閉。
作為該領域經驗豐富的資深人士,我開啟了濃縮咖啡機,朝著解決方案邁出了正確的第一步。 喝杯咖啡,我有能力解決這些問題。 首先懷疑的是,應用程序本身在崩潰之前似乎表現完全正常。 沒有錯誤,沒有警告標志,在應用程序日志中沒有任何可疑的痕跡。
我們已經進行的監視已注意到該進程已終止,并且已經重新啟動了崩潰的服務。 但是由于我的血液中已經含有咖啡因,所以我開始收集更多證據。 30分鐘后,我發現自己盯著/var/log/kern.log中的以下內容:
Jun 4 07:41:59 plumbr kernel: [70667120.897649] Out of memory: Kill process 29957 (java) score 366 or sacrifice child Jun 4 07:41:59 plumbr kernel: [70667120.897701] Killed process 29957 (java) total-vm:2532680kB, anon-rss:1416508kB, file-rss:0kB顯然,我們成為了Linux內核內部的受害者。 眾所周知,Linux是由一堆邪惡的生物(稱為“ 守護程序 ”)構建的。 這些守護程序由多個內核作業管理,其中之一似乎特別危險。 顯然,所有現代Linux內核都具有一種稱為“ 內存不足殺手 ”的內置機制,該機制可以在極低內存條件下消除您的進程。 當檢測到這種情況時,將啟動殺手并選擇要殺死的進程。 使用一組對所有過程進行評分的啟發式方法選擇目標,然后選擇得分最差的目標來殺死目標。
了解“內存不足的殺手””
默認情況下,Linux內核允許進程請求的內存比系統中當前可用的內存更多。 考慮到大多數進程實際上從未真正使用過它們分配的所有內存,因此這在世界范圍內都是有意義的。 與這種方法最簡單的比較是與電纜運營商進行比較。 他們向所有消費者提供100Mbit的下載承諾,遠遠超出了他們網絡中的實際帶寬。 再次押注的事實是,用戶將不會同時全部使用其分配的下載限制。 因此,一個10Gbit鏈路可以成功服務超過我們的簡單數學所允許的100個用戶。
如果您的某些程序正在耗盡系統內存的路徑上,這種方法的副作用是顯而易見的,這可能導致內存極低,無法分配任何頁面進行處理。 您可能已經遇到過這樣的情況,即使沒有root帳戶也無法殺死有問題的任務。 為防止此類情況,殺手啟動并確定要殺死的進程。
您可以從RedHat文檔中的本文中了解有關微調“ 內存不足殺手 ”行為的更多信息。
是什么觸發了內存不足殺手?
現在我們有了上下文,仍然不清楚是什么觸發了“殺手”,并在凌晨5點將我叫醒? 更多調查顯示:
- / proc / sys / vm / overcommit_memory中的配置允許過量使用內存–設置為1,表示每個malloc()應該成功。
- 該應用程序在EC2 m1.small實例上運行。 EC2實例默認情況下已禁用交換。
這兩個事實,再加上我們服務中流量的突然激增,導致應用程序請求越來越多的內存來支持那些額外的用戶。 過量使用配置允許為這個貪婪的過程分配越來越多的內存,最終觸發了“ 內存不足殺手 ”,他正在按照自己的意圖去做。 在半夜殺死我們的應用程序并將我叫醒。
例
當我向工程師描述這種行為時,其中一位工程師很感興趣,可以創建一個小的測試用例來重現錯誤。 在Linux上編譯并啟動以下Java代碼段時(我使用了最新的穩定Ubuntu版本):
package eu.plumbr.demo; public class OOM {public static void main(String[] args){ java.util.List l = new java.util.ArrayList(); for (int i = 10000; i < 100000; i++) {try {l.add(new int[100_000_000]);} catch (Throwable t) {t.printStackTrace();}} } }那么您將面臨同樣的內存不足:殺死進程<PID>(java)得分<SCORE>或犧牲子消息。
請注意,您可能需要調整交換文件和堆大小,在我的測試用例中,我使用了通過-Xmx2g指定的2g堆以及以下配置進行交換:
swapoff -a dd if=/dev/zero of=swapfile bs=1024 count=655360 mkswap swapfile swapon swapfile解?
有幾種方法可以處理這種情況。 在我們的示例中,我們只是將系統遷移到具有更多內存的實例。 我還考慮了允許交換,但是在咨詢了工程人員之后,我想起了一個事實,那就是JVM上的垃圾回收進程不擅長在交換下運行,因此該選項不在討論之列。
其他可能性包括微調OOM殺手 ,在幾個小實例上水平擴展負載或減少應用程序的內存需求。
如果您發現研究有趣– 在Twitter或RSS 上關注Plumbr ,我們將繼續發布有關Java內部知識的見解。
翻譯自: https://www.javacodegeeks.com/2014/06/out-of-memory-kill-process-or-sacrifice-child.html
總結
以上是生活随笔為你收集整理的内存不足:杀死进程或牺牲孩子的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 挂u盘(linux挂u盘)
- 下一篇: 大疆球形全景+电脑(大疆无人机球形全景照