1. 程式人生 > >OOM killer機制

OOM killer機制

內存

今天早晨發現我的tomcat進程無緣無故被殺死了,查看了tomcat內存監控,發現jvm內存並沒有什麽異常,並不是java內存溢出造成的,進到服務器控制臺發現
技術分享圖片
然後查了一下
這個問題的原因是由於系統內存不足導致觸發OOM保護機制。OOM Killer(Out of memory killer) 就是一層保護機制,用於避免 Linux 在內存不足的時候不至於出太嚴重的問題,將占用內存大的進程殺死,以保證系統正常運行。
還有一種情況,內存夠用,但還是觸發了 OOM 殺死進程。這裏涉及到一個 Low Memory 的知識點。內核使用 Low Memory 來跟蹤所有的內存分配。
解釋一下low memory,與之對應的有一個high memory

技術分享圖片
不過high memory只存在於32位的linux。64位系統下不會有high memory,因為64位虛擬地址空間非常大(分給kernel的也很大),完全能夠直接映射全部物理內存。可以看到我的系統位數是64位的
技術分享圖片

32位的CPU,最大尋址範圍為2^32 - 1也就是4G的線性地址空間。Linux簡化了分段機制,使得虛擬地址與線性地址總是一致的。linux一般把這個4G的地址空間劃分為兩個部分:其中0~3G為用戶程序地址空間,虛地址0x00000000到0xBFFFFFFF,供各個進程使用;3G~4G為內核的地址空間,虛擬地址0xC0000000到0xFFFFFFFF, 供內核使用。(註意,ARM架構不是3G/1G劃分的,而是2G/2G劃分。這裏以3G/1G劃分作講解)。如下圖所示:

技術分享圖片
可以看出,每個進程都有自己的私有用戶空間(0-3GB),這個空間對系統中的其他進程是不可見的。最高的1GB內核空間則由則由所有進程以及內核共享。可見,內核最多尋址1G的虛擬地址空間。
Linux 內核采用了最簡單的映射方式來映射物理內存,即把物理地址+PAGE_OFFSET按照線性關系直接映射到內核空間。PAGE_OFFSET大小為0xC000000.但是linux內核並沒有把整個1G空間用於線性映射,而只映射了最多896M物理內存,預留了最高端的128M虛擬地址空間給IO設備和其他用途。
所以,當系統物理內存較大時,超過896M的內存區域,內核就無法直接通過線性映射直接訪問了。這部分內存被稱作high memory。相應的可以映射的低端物理內存稱為Low memory.
結論:
1)high memory針對的是物理內存,不是虛擬內存。
2)high memory也是被內核管理的(有對應的page結構),只是沒有映射到內核虛擬地址空間。當內核需要分配high memory時,通過kmap等從預留的地址空間中動態分配一個地址,然後映射到high memory,從而訪問這個物理頁。high memory映射到內核地址空間一般是暫時性的映射,不是永久映射。
3)high memory和low memory一樣,都是參與內核的物理內存分配,都可以被映射到內核地址空間,也都可以被映射到用戶地址空間。
4)物理內存<896M時,沒有high memory,因為所有的內存都被kernel直接映射了。
5)64位系統下不會有high memory,因為64位虛擬地址空間非常大(分給kernel的也很大),完全能夠直接映射全部物理內存。

OOM Killer(Out of memory killer)

Linux 內核有個機制叫OOM killer(Out-Of-Memory killer),該機制會監控那些占用內存過大,尤其是瞬間很快消耗大量內存的進程,為了防止內存耗盡而內核會把該進程殺掉。
內存不足將喚醒oom_killer,挑出/proc/<pid>/oom_score最大者並將之kill掉
防止重要的系統進程觸發(OOM)機制而被殺死:可以設置參數/proc/<PID>/oom_adj為-17,可臨時關閉linux內核的OOM機制。

OOM killer機制