天天看點

JVM 在容器環境的記憶體配置

如果容器資源沒有設定任何 ​

​limits​

​ 并且Java沒有設定額外參數的話,Java應用會預設使用主控端 1/4 的記憶體作為 ​

​MaxHeapSize​

​ ,可通過如下指令驗證:

$ docker run --rm -ti 129.0.4.40/common/jdk:8 java -XX:+PrintFlagsFinal -version | grep MaxHeapSize                                                                               uintx MaxHeapSize                              := 4164943872       
測試主控端是16G記憶體,4164943872/1024/1024 ~ 4G

首先檢視使用JDK版本是否支援 ​

​UseContainerSupport​

​​ 參數,如果支援該參數,則JVM會自動讀取容器限制的記憶體值,讀取檔案:​

​/sys/fs/cgroup/memory/memory.limit_in_bytes​

該參數在 Java 8u191+,10以及更高的版本中支援
$ docker run --rm -ti 129.0.4.40/common/jdk:8 java -XX:+PrintFlagsFinal -version | grep UseContainerSupport bool UseContainerSupport = true {product}      
傳回true則表示支援,沒有任何傳回表示不支援

支援 ​

​UseContainerSupport​

實驗使用的Java版本是

java version "1.8.0_202"Java(TM) SE Runtime Environment (build 1.8.0_202-b08)Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)使用 -XX:MaxRAMPercentage 參數來配置JVM可用容器限制的資源百分比,預設是25.0 取值範圍是 0.0 到 100.0

$ docker run --rm -ti -m 2000m 129.0.4.40/common/jdk:8 java -XX:+PrintFlagsFinal -version | grep MaxHeapSize    uintx MaxHeapSize                              := 524288000$ docker run --rm -ti -m 2000m 129.0.4.40/common/jdk:8 java -XX:MaxRAMPercentage=80.0 -XX:+PrintFlagsFinal -version | grep MaxHeapSize    uintx MaxHeapSize                              := 1677721600       

如上示例顯示,如果容器限制了2000m的記憶體,預設JVM使用 1/4 的量,即500m

如果配置了 ​

​-XX:MaxRAMPercentage​

​ 參數,這裡設定為80.0,表示JVM使用限制記憶體的80%,即1600m

建議值為75.0

不支援 ​

​UseContainerSupport​

實驗使用的Java版本是

java version "1.8.0_152"Java(TM) SE Runtime Environment (build 1.8.0_152-b16)Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)

使用 ​

​-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap​

​ 參數來讓JVM讀取容器限制

不過預設即使加上這兩個參數,JVM也隻會使用容器限制記憶體的 1/4 的量,可以再添加一個參數 ​

​-XX:MaxRAMFraction​

​ ,該參數表示使用可用記憶體的基數,預設是4

JVM可用最大heap記憶體=最大可用記憶體*1/MaxRAMFraction

$ docker run --rm -ti -m4000m 129.0.4.40/common/jdk:8.1 java -XX:+PrintFlagsFinal -version | grep MaxHeapSizeuintx MaxHeapSize                              := 4164943872
$ docker run --rm -ti -m4000m 129.0.4.40/common/jdk:8.1 java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:+PrintFlagsFinal -version | grep MaxHeapSizeuintx MaxHeapSize                              := 1048576000                          
$ docker run --rm -ti -m4000m 129.0.4.40/common/jdk:8.1 java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2 -XX:+PrintFlagsFinal -version | grep MaxHeapSizeuintx MaxHeapSize                              := 2097152000      

如上示例顯示,如果容器限制了4000m的記憶體,預設JVM使用主控端 1/4 的記憶體,即4G

如果配置了 ​

​-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap​

​ 參數,則JVM使用容器限制記憶體的 1/4,即4000m*1/4=1000m

如果配置了 ​

​-XX:MaxRAMFraction=2​

​ ,則JVM使用容器限制記憶體的 1/2,即 4000m*1/2=2000m

設定 ​

​MaxRAMFraction​

​ 為1表示将容器所有記憶體配置設定給JVM,不建議這麼做,需要給其他程式預留部分記憶體