公司项目 jdk 版本为 1.8, JVM 参数是自定义设置的,gradle 中 JVM 配置如下(默认内存为 8 G):
applicationDefaultJvmArgs = ["-Xms1G", "-Xmx2G", "-Xss256k", "-Djava.awt.headless=true", "-Dfile.encoding=UTF-8",
"-XX:MetaspaceSize=256M", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=200", "-XX:G1HeapRegionSize=2M",
"-XX:+UseStringDeduplication", "-XX:+PrintStringDeduplicationStatistics",
"-XX:ParallelGCThreads=4", "-XX:ConcGCThreads=2", "-XX:MaxDirectMemorySize=1024M",
"-XX:+PrintGCDetails", "-XX:+PrintGCDateStamps", "-Xloggc:/tmp/gc.log", "-XX:+PrintTenuringDistribution",
"-XX:+DoEscapeAnalysis", "-XX:+EliminateAllocations", "-Dlogging.config=File:/config/logback.xml"]
各个参数的含义:
- -Xms1G:堆的初始内存容量为 1G
- -Xmx2G:堆的最大内存容量为 2G
- -Xss256k:Java 栈的容量为 256K(不区分虚拟机栈和本地方法栈),经测试,此时栈的高度可以达到 1500+
- -Djava.awt.headless=true:java.awt 下的类使用无头模式,跟 GUI 相关
- -Dfile.encoding=UTF-8:文件编码为 UTF-8,不指定时默认使用系统的文件编码
- MetaspaceSize=256M:元数据区容量为 256M,默认是-1,即不限制,或者说只受限于本地内存大小
- -XX:+UseG1GC:堆回收使用 G1 垃圾收集器
- -XX:MaxGCPauseMillis=200:G1 参数,GC 发生之前最大停顿时间为 200 ms,这是一个软目标,JVM 将尽最大努力实现
- -XX:+UseStringDeduplication:消除具有相同字符的重复 String 对象
- -XX:+PrintStringDeduplicationStatistics:String 重复数据删除统计分析,相关统计分析将输出到错误控制台
- -XX:ParallelGCThreads=4:G1 参数,垃圾收集器并行阶段使用线程为 4 个,默认值根据 JVM 运行的平台而定
- -XX:ConcGCThreads=2:G1 参数,并发垃圾收集器将使用的线程数为 2 个,默认值根据 JVM 运行的平台而定
- -XX:MaxDirectMemorySize=1024M:最大直接内存为 1024M,默认与 Java 堆最大值(由-Xmx 指定)一致
- -XX:+PrintGCDetails:每次垃圾回收完成后,打印一条带有更多详细信息的长消息
- -XX:+PrintGCDateStamps:发生垃圾回收时,打印相对于 JVM 启动时间的时间戳,默认关闭
- -Xloggc:/tmp/gc.log:将 GC 详细输出记录到指定文件 /tmp/gc.log,
- -XX:+PrintTenuringDistribution:开启可打印任职(存活)年龄信息,默认关闭
- -XX:+DoEscapeAnalysis:关闭转义分析的使用,默认开启
- -XX:+EliminateAllocations:关闭变量替换优化,默认开启
- -Dlogging.config=File:/config/logback.xml:log 日志使用 config 下的 logback.xml 配置文件
参数含义来源:
查看 -X
开头参数:
$ java -X
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
-Xss<size> set java thread stack size
查看所有 -XX:
开头参数的配置:
$ java -XX:+PrintFlagsFinal -version
垃圾收集器
64 位的虚拟机默认使用的就是服务端模式
,通过 java -version
可以看出(Server):
$ java -version
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
JDK 1.8 默认 JVM 参数:初始容量 Xms 128M,最大容量 Xmx 2G,使用 -XX:+UseParallelGC
。
$ java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
根据 RednaxelaFX 的回答,虽然 jconsole 显示使用 -XX:+UseParallelGC
时,但 jdk 1.8 默认会开启 XX:+UseParallelOldGC
。 此时收集器使用 Parallel Scavenge + Parallel Old
组合。
此种组合适用于注重吞吐量或者处理器资源较为稀缺的场合。
jdk1.8 可以使用更为先进的收集器 G1(Garbage First),它是 JDK 9 服务端模式默认的垃圾收集器。G1 也是遵循分代收集理论设计,它将内存分为大小相等的独立区域(Region),每个 Region 都可以根据需要,扮演新生代的 Eden 空间、Survivor 空间,或者老年代空间。回收时,不像其他收集器,只针对某个区域,Major GC(新生代)或 Full GC(老年代)或 Full GC(整个堆),而是将多个 Region 组成回收集(Collection Set)进行回收(MixedGC)。
G1 收集器跟踪每个 Region 里面的垃圾堆积的「价值」大小,价值即回收所获得的空间大小以及回收所需时间的经验值,然后在后台维护一个优先列表,再根据用户设定允许的收集停顿时间(MaxGCPauseMillis),优先处理回收价值收益最大的那些 Region,这也就是 「Garbage First」名字的由来。回收时,不追求一次把 Java 堆全部清理干净,而是追求能够应付应用的内存分配速率(Allocation Rate),只要收集的速度能跟得上对象分配的速度就行。
G1 相比 Parallel Scavenge + Parallel Old
组合的最大优点:可以指定最大收集停顿时间来调节。
Maven 项目如何使用这些参数
利用 Maven Wrapper,在 .mvn/jvm.config
中配置:
-Xms1G -Xmx2G -Xss256k -Djava.awt.headless=true -Dfile.encoding=UTF-8 -XX:MetaspaceSize=256M -XX:+UseG1GC -XX:MaxGCPauseMillis=200 ...
打包时使用 mvnw
命令,如:mvnw clean package