我不理解啊寶,為啥Java應(yīng)用遷移到容器后會出現(xiàn)OOM啊

image

JVM啟動后默認(rèn)將最大使用堆大小設(shè)置為物理內(nèi)存的四分之一,譬如一臺普通的x86服務(wù)器配置128G內(nèi)存,那么啟動在容器的內(nèi)啟動JVM會將自己最大允許使用的堆內(nèi)存調(diào)整為32G內(nèi)存,如果容器啟動時設(shè)置JVM只允許使用4G大小的內(nèi)存,那么當(dāng)JVM使用內(nèi)存超過4G后,將會導(dǎo)致內(nèi)核殺死JVM。測試代碼如下:

import JAVA.util.ArrayList; 
import JAVA.util.List; 

public class MemEat { 
    public static void main(String[] args) { 
        List l = new ArrayList<>(); 
        while (true) { 
            byte b[] = new byte[1048576]; 
            l.add(b); 
            Runtime rt = Runtime.getRuntime(); 
            System.out.println( "free memory: " + rt.freeMemory() ); 
        } 
    } 
} 

代碼非常簡單,只是通過一個死循環(huán)不停地申請內(nèi)存,如果是在JAVA 8u111版本之前,直接通過docker run -m 100m限制使用100M內(nèi)存的情況下,運行一段時間后直接被內(nèi)核殺死。輸出如下:

# JAVA MemEat 
. . . 
free memory: 1307309488 
free memory: 1306260896 
free memory: 1305212304 
free memory: 1304163712 
free memory: 1303115120 
Killed 

為了避免這種情況,可以通過“ -Xmx ”設(shè)置最大堆內(nèi)存后再次運行

# JAVA -Xmx100m MemEat 
. . . 
free memory: 8382264 
free memory: 7333672 
free memory: 6285080 
free memory: 5236488 
Exception in thread "main" JAVA.lang.OutOfMemoryError: JAVA heap space MemEat.main(MemEat.JAVA:8)

可以看到JVM由于堆內(nèi)存不足,自己退出了。這種在JVM添加參數(shù)的方式有個弊端:如果修改了容器的內(nèi)存限制,還需要調(diào)整啟動參數(shù)。為此在JAVA 8u144版本之后添加了動態(tài)調(diào)整的功能,能夠根據(jù)用戶設(shè)定的內(nèi)存限制動態(tài)調(diào)整,啟動參數(shù)如下:

# JAVA -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap MemEat 

當(dāng)我們修改了內(nèi)存參數(shù)后JVM便可以隨之調(diào)整。JAVA對于容器的支持不斷增強(qiáng)到最新的JAVA 10版本后,已經(jīng)原生支持容器環(huán)境,無需添加任何參數(shù)。不僅如此,新版JAVA 10還支持CPU在容器內(nèi)動態(tài)調(diào)整。如下所示JVM調(diào)整內(nèi)存最大堆:

# docker  run -it -m 1024M --entrypoint bash openjdk:11-jdk    
# java -XX:+PrintFlagsFinal -version | grep MaxHeapSize 
  size_t MaxHeapSize = 268435456 

可以看到上面的最大堆調(diào)整到內(nèi)存限制的四分之一,而非物理內(nèi)存的四分之一。還可以支持CPU自適應(yīng),如下所示:

# docker  run -it --CPUs 2 ---entrypoint bash openjdk:11-jdk 
jshell> Runtime.getRuntime().availableProcessors() 
$1 ==> 2 

可以看到通過JAVA的API成功地獲取到當(dāng)前設(shè)置的CPU個數(shù)。

如果是其他編程語言希望獲取到容器的CPU和內(nèi)存限制,可以通過容器內(nèi)的cgroup文件系統(tǒng),如獲取容器內(nèi)存的限制:

# cat /sys/fs/cgroup/memory/memory.limit_in_bytes 
104857600 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容