以下是JVM中Docker默认设置之间的一些常见陷阱。
首先,有很多关于JVM和容器意识的文章:
在本文中,我使用Java 11,这意味着垃圾收集器的默认值应该是G1GC! 让我们看一下默认值,JVM会根据内存大小和提供的CPU自动选择这些默认值。
基于Docker CPU的默认GC
$ docker run --cpus="2" openjdk:11-jre java -XX:+PrintFlagsFinal -version | grep -E "(MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
size_t MaxHeapSize = 5200936960 {product} {ergonomic}
bool UseG1GC = true {product} {ergonomic}
bool UseSerialGC = false {product} {default}
$ docker run --cpus="1" openjdk:11-jre java -XX:+PrintFlagsFinal -version | grep -E "(MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
size_t MaxHeapSize = 5200936960 {product} {ergonomic}
bool UseG1GC = false {product} {default}
bool UseSerialGC = true {product} {ergonomic}
注意你的Docker容器中的CPU数量; 垃圾收集器的类型可以完全不同。
基于Docker内存的默认GC
$ docker run -m 2g openjdk:11-jre java -XX:+PrintFlagsFinal -version | grep -E "(MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
size_t MaxHeapSize = 536870912 {product} {ergonomic}
bool UseG1GC = true {product} {ergonomic}
bool UseSerialGC = false {product} {default}
$ docker run -m 1g openjdk:11-jre java -XX:+PrintFlagsFinal -version | grep -E "(MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
size_t MaxHeapSize = 268435456 {product} {ergonomic}
bool UseG1GC = false {product} {default}
bool UseSerialGC = true {product} {ergonomic}
在上面的代码片段中,JVM根据提供的内存大小自动更改了默认垃圾回收器。
默认堆大小始终是可用内存的1/4!
$ docker run -m 512m openjdk:11-jre java -XX:+PrintFlagsFinal -version | grep -E "(MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
size_t MaxHeapSize = 134217728 {product} {ergonomic}
bool UseG1GC = false {product} {default}
bool UseSerialGC = true {product} {ergonomic}
$ docker run -m 256m openjdk:11-jre java -XX:+PrintFlagsFinal -version | grep -E "(MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
size_t MaxHeapSize = 132120576 {product} {ergonomic}
bool UseG1GC = false {product} {default}
bool UseSerialGC = true {product} {ergonomic}
JVM从一定数量的内存中停止选择堆大小的1/4,并开始使比率越来越小,以为你的应用程序提供更大的堆内存。
为什么选择SerialGC?
$ docker run -m 1g openjdk:11-jre java -XX:+PrintFlagsFinal -version | grep -E "(MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
size_t MaxHeapSize = 268435456 {product} {ergonomic}
bool UseG1GC = false {product} {default}
bool UseSerialGC = true {product} {ergonomic}
$ docker run -m 1g openjdk:11-jre java -Xmx700m -XX:+PrintFlagsFinal -version | grep -E "(MAX|UseSerialGC|UseG1GC|MaxHeapSize)"
size_t MaxHeapSize = 734003200 {product} {command line}
bool UseG1GC = false {product} {default}
bool UseSerialGC = true {product} {ergonomic}
这很奇怪,根据上面的示例,我们仍然应该将G1GC作为默认值,但是知道我们可以注意到JVM选择了SerialGC。 一讲,你总是必须尝试一下JVM选择了哪些默认值,并考虑它是否合理并适合你。 你会注意到JVM定义的参数被标记为符合人体工程学的JVM选项。
> 喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
> 如果你对java技术很感兴趣也可以交流学习,共同学习进步。
> 不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代
文章写道这里,欢迎完善交流。最后奉上近期整理出来的一套完整的java架构思维导图,分享给大家对照知识点参考学习。有更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java干货