https://help.aliyun.com/zh/sae/use-cases/best-practices-for-jvm-heap-size-configuration
如果JVM堆空間大小設置過大,可能會導致Linux系統的OOM Killer被激活,進而結束(kill)Java應用進程,在容器環境下可能會表現爲頻繁異常重啓。本文介紹在容器環境下JVM堆參數的配置建議,以及OOM的相關常見問題。
通過-XX:MaxRAMPercentage限制堆大小(推薦)
-
在容器環境下,Java只能獲取服務器的配置,無法感知容器內存限制。您可以通過設置
-Xmx
來限制JVM堆大小,但該方式存在以下問題:-
當規格大小調整後,需要重新設置堆大小參數。
-
當參數設置不合理時,會出現應用堆大小未達到閾值但容器OOM被強制關閉的情況。
應用程序出現OOM問題時,會觸發Linux內核的OOM Killer機制。該機制能夠監控佔用過大內存,尤其是瞬間消耗大量內存的進程,然後它會強制關閉某項進程以騰出內存留給系統,避免系統立刻崩潰。
-
-
推薦的JVM參數設置。
-XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof
參數說明如下。
參數
說明
-XX:+UseContainerSupport
使用容器內存。允許JVM從主機讀取cgroup限制,例如可用的CPU和RAM,並進行相應的配置。當容器超過內存限制時,會拋出OOM異常,而不是強制關閉容器。
-XX:InitialRAMPercentage
設置JVM使用容器內存的初始百分比。建議與
-XX:MaxRAMPercentage
保持一致,推薦設置爲70.0。-XX:MaxRAMPercentage
設置JVM使用容器內存的最大百分比。由於存在系統組件開銷,建議最大不超過75.0,推薦設置爲70.0。
-XX:+PrintGCDetails
輸出GC詳細信息。
-XX:+PrintGCDateStamps
輸出GC時間戳。日期形式,例如2019-12-24T21:53:59.234+0800。
-Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log
GC日誌文件路徑。需保證Log文件所在容器路徑已存在,建議您將該容器路徑掛載到NAS目錄或收集到SLS,以便自動創建目錄以及實現日誌的持久化存儲。
-XX:+HeapDumpOnOutOfMemoryError
JVM發生OOM時,自動生成Dump文件。
-XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof
Dump文件路徑。需保證Dump文件所在容器路徑已存在,建議您將該容器路徑掛載到NAS目錄,以便自動創建目錄以及實現日誌的持久化存儲。
-
使用
-XX:+UseContainerSupport
參數需JDK 8u191+、JDK 10及以上版本。 -
JDK 11版本下日誌相關的參數
-XX:+PrintGCDetails
、-XX:+PrintGCDateStamps
、-Xloggc:$LOG_PATH/gc.log
參數已廢棄,請使用參數-Xlog:gc:$LOG_PATH/gc.log
代替。 -
Dragonwell 11不支持
${POD_IP}
變量。 -
如果您沒有將/home/admin/nas容器路徑掛載到NAS目錄,則必須保證該目錄在應用啓動前已存在,否則將不會產生日誌文件。
-
通過-Xms -Xmx限制堆大小
-
您可以通過設置
-Xms
和-Xmx
來限制堆大小,但該方式存在以下兩個問題:-
當規格大小調整後,需要重新設置堆大小參數。
-
當參數設置不合理時,會出現應用堆大小未達到閾值但容器OOM被強制關閉的情況。
應用程序出現OOM問題時,會觸發Linux內核的OOM Killer機制。該機制能夠監控佔用過大內存,尤其是瞬間消耗大量內存的進程,然後它會強制關閉某項進程以騰出內存留給系統,避免系統立刻崩潰。
-
-
推薦的JVM參數設置。
-Xms2048m -Xmx2048m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof
參數說明如下。
參數
說明
-Xms
設置JVM初始內存大小。建議與
-Xmx
相同,避免每次垃圾回收完成後JVM重新分配內存。-Xmx
設置JVM最大可用內存大小。爲避免容器OOM,請爲系統預留足夠的內存大小。
-XX:+PrintGCDetails
輸出GC詳細信息。
-XX:+PrintGCDateStamps
輸出GC時間戳。日期形式,例如2019-12-24T21:53:59.234+0800。
-Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log
GC日誌文件路徑。需保證Log文件所在容器路徑已存在,建議您將該容器路徑掛載到NAS目錄或收集到SLS,以便自動創建目錄以及實現日誌的持久化存儲。
-XX:+HeapDumpOnOutOfMemoryError
JVM發生OOM時,自動生成Dump文件。
-XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof
Dump文件路徑。需保證Dump文件所在容器路徑已存在,建議您將該容器路徑掛載到NAS目錄,以便自動創建目錄以及實現日誌的持久化存儲。
-
推薦的堆大小設置。
內存規格大小
JVM堆大小
1 GB
600 MB
2 GB
1434 MB
4 GB
2867 MB
8 GB
5734 MB
通過ossutil下載堆轉儲文件
-
掛載容器日誌目錄至NAS。具體操作,請參見設置NAS存儲。
-
設置JVM參數。
其中Dump文件路徑/home/admin/nas爲NAS掛載目錄:
-Xms2048m -Xmx2048m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof
-
當應用發生OOM時,會生成堆轉儲文件到NAS掛載目錄,您可以利用ossutil工具,將該Dump文件下載到本地進行分析。具體操作,請參見通過日誌上傳下載診斷應用。
常見問題
容器出現137退出碼的含義是什麼?
當容器使用內存超過限制時,會出現容器OOM,導致容器被強制關閉。此時業務應用內存可能並未達到JVM堆大小上限,所以不會產生Dump日誌。建議您調小JVM堆大小的上限,爲容器內其他系統組件預留足夠多的內存空間。
爲什麼發生OOM卻沒有生成Dump文件?
當發生OOM Killer時,並不一定會發生JVM OOM,所以不會生成Dump文件。您可以採取以下方式來避免這種情況。
-
如果是Java應用,可以適當調小JVM的堆內存大小。具體配置,請參見本文。
-
如果是非Java應用,可以調整實例規格,保證充裕的內存資源。具體配置,請參見變更實例規格。
堆大小和規格內存的參數值可以相同嗎?
不可以。因爲系統自身組件存在內存開銷,例如使用SLS進行日誌收集(設置日誌收集至SLS)時會佔用一小部分的內存空間,所以不能將JVM堆大小設置爲和規格內存大小相同的數值,需要爲這些系統組件預留足夠的內存空間。
在JDK 8版本下設置-XX:MaxRAMPercentage值爲整數時報錯怎麼處理?
這是JDK 8的一個Bug。具體信息,請參見Java Bug Database。例如,在JDK 8u191版本下,設置-XX:MaxRAMPercentage=70
,此時JVM會啓動報錯。
解決方案如下:
-
方式一:設置
-XX:MaxRAMPercentage
爲70.0
。如果您使用了
-XX:InitialRAMPercentage
或-XX:MinRAMPercentage
,參數值同樣不可設置爲整數,需按照方式一的形式來設置。 -
方式二:升級JDK版本至JDK 10及以上版本。
爲什麼JVM參數設置了6 GB,但是內存使用率卻很低?
雖然JVM參數已設置-Xms6g -Xmx6g
,但是操作系統不會馬上分配6 GB的物理內存,需要實際使用後才分配。因此,內存使用率在應用啓動的時候,會相對較低,後續會出現攀爬現象。