如果容器资源没有设置任何 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 MaxHeapSize
uintx MaxHeapSize := 4164943872
$ docker run --rm -ti -m4000m 129.0.4.40/common/jdk:8.1 java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:+PrintFlagsFinal -version | grep MaxHeapSize
uintx 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 MaxHeapSize
uintx 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,不建议这么做,需要给其他程序预留部分内存Java 10 移除了
-XX:{Initial|Min|Max}RAMFraction
参数
对于 Java SE 8u121
以及之前的版本这些参数都不生效,只能通过 -Xms1000m -Xmx2000m
这种方式进行限制
-Xmx
参数即使设置了2000m,JVM也会分配比2000m多的内存,如果想将JVM完全限制在2000m以内,需要使用-XX:MaxRAM
参数