本文來自于HeapDump性能社區! !有性能問題,上HeapDump性能社區!
正文:
為了理解這個錯誤,我們需要回顧一下操作系統的基礎知識。如您所知,操作系統是建立在進程的概念之上的。這些進程由幾個內核作業引導,在這種特殊情況下,我們對其中一個名為“OOM Killer”的作業很感興趣。
此內核作業可以在極低的內存條件下消滅您的進程。當檢測到這種情況時,內存不足殺手會被激活并選擇一個進程來殺死。使用一組啟發式對所有進程進行評分并選擇得分最差的進程來選擇目標。因此,OOM:Kill process or sacrifice child與我們的OOM 手冊中涵蓋的其他錯誤不同,因為它不是由 JVM 觸發或代理的,而是內置于操作系統內核中的安全網。
內存不足 linux 內核
輸出存儲器:Kill process or sacrifice child時可用虛擬內存(包括交換空間)被產生誤差被消耗到整個操作系統穩定性被投入風險的程度。在這種情況下,OOM Killer會選擇流氓進程并殺死它。
1,是什么原因造成的?
默認情況下,Linux 內核允許進程請求比系統中當前可用的內存更多的內存??紤]到大多數進程實際上從未使用過它們分配的所有內存,這在世界上都是有意義的。與這種方法最簡單的比較是寬帶運營商。他們向所有消費者出售 100Mbit 下載承諾,遠遠超過他們網絡中的實際帶寬。賭注再次取決于用戶不會同時全部使用他們分配的下載限制這一事實。因此,一個 10Gbit 鏈路可以成功地為超過 100 個用戶提供我們簡單的數學所允許的服務。
如果您的某些程序正在耗盡系統內存,則這種方法的副作用是可見的。這可能導致內存極低的情況,即無法分配任何頁面來處理。您可能遇到過這樣的情況,即使是 root 帳戶也無法殺死有問題的任務。為了防止出現這種情況,殺手會激活并識別流氓進程被殺死。
您可以在這篇來自 RedHat 文檔的文章中閱讀有關微調“OOM Killer”行為的更多信息。
現在我們有了上下文,你怎么知道是什么觸發了“killer”并在凌晨 5 點叫醒你?一種常見的激活觸發器隱藏在操作系統配置中。當您檢查/proc/sys/vm/overcommit_memory 中的配置時,您會得到第一個提示——此處指定的值表示是否允許所有 malloc() 調用成功。請注意,proc 文件系統中參數的路徑因受更改影響的系統而異。
過度使用配置允許為這個流氓進程分配越來越多的內存,這最終會觸發“OOM Killer”來做它應該做的事情。
2,舉個例子
當您在 Linux 上編譯并啟動以下 Java 代碼片段時(我使用了最新的穩定版 Ubuntu):
package eu.plumbr.demo;
public class OOM {
public static void main(String[] args){
java.util.List<int[]> 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();
}
}
}
}
那么您將在系統日志(在我們的示例中為/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
請注意,您可能需要調整交換文件和堆大小,在我們的測試用例中,我們使用了-Xmx2g指定的 2g 堆并具有以下交換配置:
swapoff -a
dd if=/dev/zero of=swapfile bs=1024 count=655360
mkswap swapfile
swapon swapfile
3,解決辦法是什么?
有幾種方法可以處理這種情況。解決該問題的第一個也是最直接的方法是將系統遷移到具有更多內存的實例。
其他可能性包括微調 OOM 殺手、跨幾個小實例水平擴展負載或減少應用程序的內存需求。
我們不熱衷推薦的一種解決方案是增加交換空間。當您回憶起 Java 是一種垃圾收集語言時,此解決方案似乎已經不那么有利可圖了。現代 GC 算法在物理內存中運行時是高效的,但在處理交換分配時效率受到打擊。交換可以將 GC 暫停的長度增加幾個數量級,因此在跳轉到此解決方案之前應該三思而后行。
Java OOM系列專題:
第一篇:Java OOM 原理篇 : 什么是 Java OOM
第二篇:Java OOM 基礎篇:常見的OutOfMemoryError 場景一:Java heap space 堆溢出問題詳解
第三篇:Java OOM 基礎篇:常見的OutOfMemoryError 場景二 : GC overhead limit exceeded 問題詳解
第四篇:Java OOM 基礎篇:常見的OutOfMemoryError 場景三: PermGen space 永久空間問題詳解
第五篇:Java OOM 基礎篇:常見的OutOfMemoryError 場景四: Permgen size 元空間問題詳解
第六篇:Java OOM 實戰篇:應用故障之Java heap space 堆溢出實戰