通过整体学习JVM参数以及一个应用所需要配置的JVM参数,可以了解项目运行时要配置那些JVM、并根据运行时特性和环境,进行JVM参数调优。
-XX开头的配置是JVM都支持的配置
参数类型:
- bool类型的配置:+开启、-关闭
- 键值型的配置:等号赋值
序号 | 参数 | 说明 |
---|---|---|
1 | -XX:+PrintGC | 打印简单GC日志 |
2 | -XX:+PrintGCDetails | 打印详细GC日志 |
3 | -XX:+PrintGCDateStamps | 显示每次GC的日期时间 |
4 | -XX:+UseGCLogFileRotation | GC日志文件循环使用(比如,5个日志文件循环使用) |
5 | -XX:GCLogFileSize=100M | 每个GC日志文件的默认大小 |
6 | -XX:NumberOfGCLogFiles=5 | GC日志文件数,可以设置循环使用 |
7 | -XX:-OmitStackTraceInFastThrow | 关闭栈异常信息快速抛出,从而记录详细的栈异常以便跟踪。 |
8 | -XX:HeapDumpPath=/opt/logs/appid | 指定导出堆信息时的路径或文件名(路径要存在) |
9 | -XX:+HeapDumpOnOutOfMemoryError | 出现内存溢出时,Dump出当前的内存快照 |
(二)见 -x 参数设置
序号 | 参数 | 说明 |
---|---|---|
1 | -XX:MetaspaceSize=128m | 元空间的初始大小,不断扩容并首次超过这个值时会进行FGC,JVM会动态调整这个值 |
2 | -XX:MaxMetaspaceSize=256m | 元空间的最大值,超过最大值时会抛异常出来,加载的类越多,元空间使用的内存越多,元空间使用 Native Memory。 |
3 | -XX:MinHeapFreeRatio=30 | 指定空闲堆空间的最小百分比,如果实际空闲堆空间小于此值则需要对堆进行扩容 ,Xmx==Xms 的情况下无效 |
4 | -XX:MaxHeapFreeRatio=50 | 指定空闲堆空间最大百分比 ,如果实际空闲堆空间大于此值则需要对对堆空间进行缩容,Xmx==Xms 的情况下无效 |
序号 | 参数 | 说明 |
---|---|---|
1 | -XX:+UseG1GC | 使用G1GC |
2 | -XX:MaxGCPauseMillis=200 | 最大GC暂停时间,G1GC尽量保证软实时性; |
3 | -XX:ParallelGCThreads=4 | (在STW阶段工作的)最大并行GC线程数 |
4 | -XX:ConcGCThreads=4 | (在非STW期间的GC工作线程数)最大并发GC线程数 |
-XX:MaxGCPauseMillis 解释
这是一个软性目标,G1会尽量达成,如果达不成,会逐渐做自我调整。
对于Young GC来说,会逐渐减少Eden区个数,减少Eden空间那么Young GC的处理时间就会相应减少;
对于Mixed GC,G1会调整每次Choose Cset的比例,默认最大值是10%,当然每次选择的Cset少了,所要经历的Mixed GC的次数会相应增加。
同时减少Eden的总空间时,就会更加频繁的触发Young GC,也就是会加快Mixed GC的执行频率,因为Mixed GC是由Young GC触发的,或者说借机同时执行的。
频繁GC会对对应用的吞吐量造成影响,每次Mixed GC回收时间太短,回收的垃圾量太少,可能最后GC的垃圾清理速度赶不上应用产生的速度,那么可能会造成串行的Full GC,这是要极力避免的。所以暂停时间肯定不是设置的越小越好.
当然也不能设置的偏大,这样可能会导致一次全部并发标记后触发的Mixed GC次数变少,但每次的时间变长,STW时间变长,对应用的影响更加明显。
序号 | 参数 | 说明 |
---|---|---|
1 | -XX:+AlwaysPreTouch | jvm启动的时候分配物理内存 |
2 | -XX:+ScavengeBeforeFullGC | Full gc前先执行Minor gc |
3 | -XX:+DisableExplicitGC | 禁止显式执行GC,不允许通过代码来触发GC。 |
4 | -XX:InitiatingHeapOccupancyPercent=70 |
1. 当整个堆占用超过某个百分比时,就会触发并发GC周期;
2. 如果项目没有大的cpu负载压力,可以适当降低这个值,带来的好处就是提前开始Concurrent Marking Cycle Phases,年轻代/老年代回收也会提前开始,这样有利于防止年轻代晋升老年代失败(老年代容量不足)而触发Full GC;
|
5 | -XX:+UseTLAB | 开启线程专用内存分配区域 |
-XX:+UseTLAB
TLAB的全称是Thread Local Allocation Buffer,即线程分配缓存区。
由于对象一般会分配在堆上,而堆是全局共享的。所以在同一时间,可能会有多个线程在堆上申请空间。
而每次对象分配都必须要进行同步,在竞争激烈的场合分配的效率又会进一步下降。
JVM使用TLAB来避免多线程冲突,在给对象分配内存时,每个线程使用自己的TLAB,这样可以避免线程同步。
-X 开头特用于java HotSpot虚拟机的通用选项
JVM运行时内存区设置(二) + 日志设置
序号 | 参数 | 说明 |
---|---|---|
1 | -Xmx2g | JVM 最大堆内存 |
2 | -Xms2g | JVM 初始堆内存。通常这两个配置参数相等,避免每次空间不足,动态扩容带来的影响。 |
3 | -Xss256k | 设置每个线程的栈大小 |
4 | -Xloggc:$APP_LOG_DIR/gc-%t.log | gc日志生成目录 |
在启动一个java程序时设置的系统属性,参数会在jvm启动java应用程序之前赋值给应用程序
也可以通过使用System.setProperty(key, value)
来完成。
-Djava.util.concurrent.ForkJoinPool.common.parallelism=480
-DdodpPipelineWorker.main.class=${MAIN_CLASS}
-Dconfig=$APP_HOME/config
-Dfile.encoding=UTF-8
-Dspring.liquibase.enabled=false
-Ddubbo.application.logger=log4j2
-Dlogging.config=${APP_HOME}/config/log4j2.xml
-DcwAppHome=${APP_HOME}
整个堆大小的计算公式: JVM 堆大小 = 年轻代大小+年老代大小+持久代大小。
增大新生代大小就会减少对应的老年代大小,设置-Xmn值对系统性能影响较大,所以如果设置新生代大小的调整,则需要严格的测试调整。
1. Xmn用于设置新生代的大小。过小会增加Minor GC频率,过大会减小老年代的大小。一般设为整个堆空间的1/4或1/3.
|
2.一般来说,MaxPermSize设为64MB可以满足绝大多数的应用了。若依然出现方法区溢出,则可以设为128MB。若128MB还不能满足需求,那么就应该考虑程序优化了,减少动态类的产生。
|
3. 当Xms=Xmx,可以使得堆相对稳定,避免不停震荡
|
- 引用计数法: 会有循环引用的问题,不推荐;
- Mark-Sweep: 标记清除。根可达判断,最大的问题是产生空间碎片;
- Copying: 复制算法。对于短命对象来说有用,否则需要复制大对象,效率低。如Java的新生代堆空间中就是使用了它(survivor空间的from和to区);
- Mark-Compact: 标记整理。对于老年对象来说有用,无需复制,不会产生内存碎片
吞吐量:应用耗时和总运行耗时的比值;
停顿时间:垃圾回收的时候,由于Stop the World,应用程序的所有线程会挂起,造成应用停顿。
吞吐量和停顿时间是成反比的
- 对于后端服务:吞吐量优先考虑(推荐:并发垃圾回收)
- 对于前端应用:响应时间优先考虑,减少STW时间(推荐:并发垃圾回收)
JVM_OPTS="
# server模式 + 堆 、栈大小
-server
-Xms${ENV_JVM_HEAP_SIZE:-${INNER_JVM_HEAP_SIZE_MIN}}
-Xmx${ENV_JVM_HEAP_SIZE:-${INNER_JVM_HEAP_SIZE_MAX}}
-Xss256k
# 相关调优设置
-XX:+AlwaysPreTouch
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=70
-XX:+ScavengeBeforeFullGC
-XX:+DisableExplicitGC
#日志相关
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=100m
-Xloggc:$APP_LOG_DIR/gc-%t.log
-Xbootclasspath/a:$APP_HOME/config
#程序参数
-Djava.util.concurrent.ForkJoinPool.common.parallelism=480
-DdodpPipelineWorker.main.class=${MAIN_CLASS}
-Dconfig=$APP_HOME/config
-Dfile.encoding=UTF-8
-Dspring.liquibase.enabled=false
-Ddubbo.application.logger=log4j2
-Dlogging.config=${APP_HOME}/config/log4j2.xml
-DcwAppHome=${APP_HOME}
"