本文來自于HeapDump性能社區(qū)酌儒! !有性能問題枯途,上HeapDump性能社區(qū)忌怎!
正文:
為了理解這個(gè)錯(cuò)誤,我們需要回顧一下操作系統(tǒng)的基礎(chǔ)知識(shí)酪夷。如您所知榴啸,操作系統(tǒng)是建立在進(jìn)程的概念之上的。這些進(jìn)程由幾個(gè)內(nèi)核作業(yè)引導(dǎo)晚岭,在這種特殊情況下鸥印,我們對(duì)其中一個(gè)名為“OOM Killer”的作業(yè)很感興趣。
此內(nèi)核作業(yè)可以在極低的內(nèi)存條件下消滅您的進(jìn)程坦报。當(dāng)檢測(cè)到這種情況時(shí)库说,內(nèi)存不足殺手會(huì)被激活并選擇一個(gè)進(jìn)程來殺死。使用一組啟發(fā)式對(duì)所有進(jìn)程進(jìn)行評(píng)分并選擇得分最差的進(jìn)程來選擇目標(biāo)片择。因此潜的,OOM:Kill process or sacrifice child與我們的OOM 手冊(cè)中涵蓋的其他錯(cuò)誤不同,因?yàn)樗皇怯?JVM 觸發(fā)或代理的字管,而是內(nèi)置于操作系統(tǒng)內(nèi)核中的安全網(wǎng)啰挪。
內(nèi)存不足 linux 內(nèi)核
輸出存儲(chǔ)器:Kill process or sacrifice child時(shí)可用虛擬內(nèi)存(包括交換空間)被產(chǎn)生誤差被消耗到整個(gè)操作系統(tǒng)穩(wěn)定性被投入風(fēng)險(xiǎn)的程度信不。在這種情況下,OOM Killer會(huì)選擇流氓進(jìn)程并殺死它亡呵。
1抽活,是什么原因造成的?
默認(rèn)情況下政己,Linux 內(nèi)核允許進(jìn)程請(qǐng)求比系統(tǒng)中當(dāng)前可用的內(nèi)存更多的內(nèi)存√统睿考慮到大多數(shù)進(jìn)程實(shí)際上從未使用過它們分配的所有內(nèi)存歇由,這在世界上都是有意義的。與這種方法最簡單的比較是寬帶運(yùn)營商果港。他們向所有消費(fèi)者出售 100Mbit 下載承諾沦泌,遠(yuǎn)遠(yuǎn)超過他們網(wǎng)絡(luò)中的實(shí)際帶寬。賭注再次取決于用戶不會(huì)同時(shí)全部使用他們分配的下載限制這一事實(shí)辛掠。因此谢谦,一個(gè) 10Gbit 鏈路可以成功地為超過 100 個(gè)用戶提供我們簡單的數(shù)學(xué)所允許的服務(wù)。
如果您的某些程序正在耗盡系統(tǒng)內(nèi)存萝衩,則這種方法的副作用是可見的回挽。這可能導(dǎo)致內(nèi)存極低的情況,即無法分配任何頁面來處理猩谊。您可能遇到過這樣的情況千劈,即使是 root 帳戶也無法殺死有問題的任務(wù)。為了防止出現(xiàn)這種情況牌捷,殺手會(huì)激活并識(shí)別流氓進(jìn)程被殺死墙牌。
您可以在這篇來自 RedHat 文檔的文章中閱讀有關(guān)微調(diào)“OOM Killer”行為的更多信息。
現(xiàn)在我們有了上下文暗甥,你怎么知道是什么觸發(fā)了“killer”并在凌晨 5 點(diǎn)叫醒你喜滨?一種常見的激活觸發(fā)器隱藏在操作系統(tǒng)配置中。當(dāng)您檢查/proc/sys/vm/overcommit_memory 中的配置時(shí)撤防,您會(huì)得到第一個(gè)提示——此處指定的值表示是否允許所有 malloc() 調(diào)用成功虽风。請(qǐng)注意,proc 文件系統(tǒng)中參數(shù)的路徑因受更改影響的系統(tǒng)而異寄月。
過度使用配置允許為這個(gè)流氓進(jìn)程分配越來越多的內(nèi)存焰情,這最終會(huì)觸發(fā)“OOM Killer”來做它應(yīng)該做的事情。
2剥懒,舉個(gè)例子
當(dāng)您在 Linux 上編譯并啟動(dòng)以下 Java 代碼片段時(shí)(我使用了最新的穩(wěn)定版 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();
}
}
}
}
那么您將在系統(tǒng)日志(在我們的示例中為/var/log/kern.log)中遇到類似于以下內(nèi)容的錯(cuò)誤:
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
請(qǐng)注意内舟,您可能需要調(diào)整交換文件和堆大小,在我們的測(cè)試用例中初橘,我們使用了-Xmx2g指定的 2g 堆并具有以下交換配置:
swapoff -a
dd if=/dev/zero of=swapfile bs=1024 count=655360
mkswap swapfile
swapon swapfile
3验游,解決辦法是什么充岛?
有幾種方法可以處理這種情況。解決該問題的第一個(gè)也是最直接的方法是將系統(tǒng)遷移到具有更多內(nèi)存的實(shí)例耕蝉。
其他可能性包括微調(diào) OOM 殺手崔梗、跨幾個(gè)小實(shí)例水平擴(kuò)展負(fù)載或減少應(yīng)用程序的內(nèi)存需求。
我們不熱衷推薦的一種解決方案是增加交換空間垒在。當(dāng)您回憶起 Java 是一種垃圾收集語言時(shí)蒜魄,此解決方案似乎已經(jīng)不那么有利可圖了。現(xiàn)代 GC 算法在物理內(nèi)存中運(yùn)行時(shí)是高效的场躯,但在處理交換分配時(shí)效率受到打擊谈为。交換可以將 GC 暫停的長度增加幾個(gè)數(shù)量級(jí),因此在跳轉(zhuǎn)到此解決方案之前應(yīng)該三思而后行踢关。
Java OOM系列專題:
第一篇:Java OOM 原理篇 : 什么是 Java OOM
第二篇:Java OOM 基礎(chǔ)篇:常見的OutOfMemoryError 場(chǎng)景一:Java heap space 堆溢出問題詳解
第三篇:Java OOM 基礎(chǔ)篇:常見的OutOfMemoryError 場(chǎng)景二 : GC overhead limit exceeded 問題詳解
第四篇:Java OOM 基礎(chǔ)篇:常見的OutOfMemoryError 場(chǎng)景三: PermGen space 永久空間問題詳解
第五篇:Java OOM 基礎(chǔ)篇:常見的OutOfMemoryError 場(chǎng)景四: Permgen size 元空間問題詳解
第六篇:Java OOM 實(shí)戰(zhàn)篇:應(yīng)用故障之Java heap space 堆溢出實(shí)戰(zhàn)
第七篇:Java OOM 高級(jí)篇:體驗(yàn)了一把線上CPU100%及應(yīng)用OOM的排查和解決過程