关于容器内JVM的实验
默认的,jvm的初始内存Xms为服务器内存的1/64,最大内存Xmx为内存的1/4
实验验证下docker中jvm的内存使用情况
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @SpringBootApplication public class OomApplication {
public static void main(String[] args) { System.out.println("==============="); SpringApplication.run(OomApplication.class, args); System.out.println("********************"); oom(); }
private static void oom() { Runtime rt = Runtime.getRuntime(); //返回java虚拟机中的初始内存总量Xms,默认应该是机器内存的1/64 long totalMemory = rt.totalMemory(); //返回java虚拟机可以使用的最大内存量Xms,默认应该是机器的1/4 long maxMemory = rt.maxMemory(); System.out.println("Total_Memory(-Xms ) = " + totalMemory + " 字节 " + (totalMemory / (double) 1024 / 1024) + "MB"); System.out.println("Max_Memory(-Xmx ) = " + maxMemory + " 字节 " + (maxMemory / (double) 1024 / 1024) + "MB");
List l = new ArrayList<>(); while (true) { byte b[] = new byte[1048576]; l.add(b); System.out.println("使用的内存:"+ rt.totalMemory() / (double) 1024 / 1024 + "M,free memory: " + rt.freeMemory() / (double) 1024 / 1024); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
}
|
限制docker容器的内存
Dockerfile
1 2 3 4 5
| FROM openjdk:8u191-jdk-alpine3.9 COPY ./oom-1.0.0.jar / RUN apk add --no-cache tini ENTRYPOINT ["tini"] CMD ["java", "-jar", "oom-1.0.0.jar"]
|
1
| docker run -d -m 1000m --memory-swap 1000m --name myjdk myjdk:1.0.0
|
-m 限制容器可用内存为1000m
–memory-swap是容器可以使用的物理内存和可以使用的 swap 之和,设置的和memory一样大,就是不允许使用swap
设置为0,或者不设置,表示swap为memory的2倍
-1,它表示容器程序使用内存的受限,而可以使用的 swap 空间使用不受限制(宿主机有多少 swap 容器就可以使用多少)。
打印的日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| Total_Memory(-Xms ) = 16252928 字节 15.5MB Max_Memory(-Xmx ) = 253427712 字节 241.6875MB 使用的内存:15.5M,free memory: 8.396034240722656 使用的内存:15.5M,free memory: 7.396018981933594 使用的内存:15.5M,free memory: 6.396003723144531 使用的内存:15.5M,free memory: 5.395988464355469 使用的内存:15.5M,free memory: 4.454139709472656 使用的内存:15.5M,free memory: 3.4541244506835938 使用的内存:15.5M,free memory: 2.4541091918945312 使用的内存:15.5M,free memory: 1.4540939331054688 使用的内存:31.47265625M,free memory: 17.306068420410156 使用的内存:31.47265625M,free memory: 16.306053161621094 ... 使用的内存:31.47265625M,free memory: 2.3054122924804688 使用的内存:67.7265625M,free memory: 37.36358642578125 使用的内存:67.7265625M,free memory: 36.36357116699219 ... 使用的内存:67.7265625M,free memory: 3.3696060180664062 使用的内存:149.89453125M,free memory: 84.09593200683594 使用的内存:149.89453125M,free memory: 83.09591674804688 ... 使用的内存:149.89453125M,free memory: 8.10455322265625 使用的内存:149.89453125M,free memory: 7.1045379638671875 使用的内存:241.6875M,free memory: 98.41573333740234 使用的内存:241.6875M,free memory: 98.41573333740234 ... 使用的内存:241.6875M,free memory: 0.5089797973632812 Exception in thread "main" java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) at org.springframework.boot.loader.Launcher.launch(Launcher.java:107) at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) Caused by: java.lang.OutOfMemoryError: Java heap space at com.yunsheng.demo.OomApplication.oom(OomApplication.java:30) at com.yunsheng.demo.OomApplication.main(OomApplication.java:16) ... 8 more
|
看到初始Xms确实为1G内存的1/64,Xmx为1G内存的1/4
然后内存耗尽之后,申请的基本上是当前内存的一倍还多一点。
验证jdk命令
进入容器,实现jps,jstat等jdk命令可以使用
jmap进行堆dump也是可以的

验证异常退出dump
Dockerfile
1 2 3 4 5 6 7 8
| FROM openjdk:8u191-jdk-alpine3.9 COPY ./oom-1.0.0.jar / COPY ./start.sh / WORKDIR / RUN apk add --no-cache tini ENTRYPOINT ["tini"] #CMD ["java", "-jar", "oom-1.0.0.jar"] CMD sh start.sh
|
在程序jvm的启动参数中增加异常退出时进行堆转储
1
| nohup java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/my-heap-dump.hprof -jar oom-1.0.0.jar > log.log 2>&1 &
|

验证ok
测试s2i方式打镜像启动
同样的代码
同样的容器启动命令
发现s2i方式启动的java进行,其内存的设置是依赖的物理机内存