JVM调优实操步骤
前置知识
1、堆中各大小的参数设置
-Xms32M 初始堆大小
-Xmx32M 最大堆大小
-Xmn16M 新生代大小
-XX:MetaspaceSize=256M 设置元空间的初始值
-XX:MaxMetaspaceSize=256M 设置最大元空间大小
-XX:SurvivorRatio=8 设置Eden和survivor的比例
2、垃圾收集器的选择
-XX:+UseSerialGC 使用serial & serialOld
-XX:+UseParallelGC 使用 Parallel Scavenge & ParallelOld
-XX:+UseConcMarkSweepGC 使用 ParNew & CMS
-XX:+UseG1GC 使用G1垃圾收集器
3、开启GC日志
---JDK8:
- -XX:+PrintGCDetails
- -XX:+PrintGCDateStamps
- -Xloggc:D:\gc\gc-%t.log
- -XX:+UseGCLogFileRotation
- -XX:NumberOfGCLogFiles=2
- -XX:GCLogFileSize=1M
JDK9---:
- -Xlog:gc=debug:file=gc.log:uptimemillis,pids:filecount=5,filesize=1024
4、开启OOM的时候触发快照
1、自动
- -XX:+HeapDumpOnOutOfMemoryError
- -XX:HeapDumpPath=/usr/local
2、如果没有开启可手动
- jmap -dump:format=b,file=名称.hprof
5、GCeasy,在线人工智能分析GC日志
- 吞吐量
- GC延迟信息(平均值、最高值、用时分布)
- GC次数,GC原因
- 各区内存使用的峰值
- GC后的堆内存大小连续图(整堆、年轻代、老年代、元空间)
- GC前的对内存大小连续图(整堆、年轻代、老年代、元空间)
- GC回收垃圾连续图
- GC原因列表
6、OOM类型
- java heap space 堆内存溢出,根据dump快照分析可疑对象,定位代码进行解决
- Metaspace ①动态创建的类太多,利用jstack查看堆栈信息,定位代码。②空间设置过小,增加空间
- GC over head limit excepted 默认情况下,jvm用了98%的时间回收垃圾,回收效果不到%2,(内存泄漏、大对象或者长生命周期对象导致的)
- Direct Buffer Memory,①直接内存设置过小(-XX:MaxDirectMemorySize 默认64M) ②使用直接内存的时候没有释放
- unable to create new native thread,①查看堆栈,确定线程数,不多就查看系统允许的线程数,多就去查看什么线程创建过多,定位代码,分析解决
- request {} byte for {} out of swap 使用到了直接内存,分析是否内存泄漏,分析大对象或者长期存活对象,定位代码,进行解决
调优思维
- 首先不对JVM各区大小进行设置,使用默认值,开启GC日志,开启OOM的时候触发快照
- 运行一段时间,利用GCeasy分析GC日志,在正常运行的情况下,获取到FullGC后的老年代的大小(OldSizeAfterFullGC)
- 设置-Xms和-Xmx的大小为 3~4 倍 的 OldSizeAfterFullGC
- 设定-Xmn的大小为 1~1.5倍的 OldSizeAfterFullGC
- 设定-XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 大小为 FullGC后的元空间使用大小的 1.2~1.5倍
- 继续运行
- 分析日志,如果MinorGC过于频繁则增加 -Xmn的大小,如果MinorGC的间隔时间太长,则减少新生代的大小,具体测试决定
线上解决频繁FullGC问题
- 利用GCeasy分析GC日志
- 了解整体性能(吞吐量、GC延迟)
- 查看FullGC频率,确定是频繁FullGC
- 查看FullGC的原因,杜绝手动调用System.gc()
- 查看元空间在GC前后的占用空间的统计图,确定是否因为元空间被打满导致的频繁FullGC
- 查看整堆在GC后的占用空间统计图,看是否持续上涨,如果是是内存泄漏问题
- 查看垃圾回收数据量的统计图,确定是否回收了数据,如果回收了数据,但是堆数据还是持续上涨到最大值,考虑是死循环,使用top查看高CPU占用进程获取pid,使用top -Hp pid获取进程内高cpu占用的线程pid,printf "%x\n" pid 将线程pid转换为16进制,用jstack 去dump指定进程,根据线程pid找到数据,定位代码,进行分析
- 回收没有效果,dump堆内存,利用MAT工具进行分析,定义可疑大对象或者长期存活的对象,定位到代码,进行分析