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日志

  1. 吞吐量
  2. GC延迟信息(平均值、最高值、用时分布)
  3. GC次数,GC原因
  4. 各区内存使用的峰值
  5. GC后的堆内存大小连续图(整堆、年轻代、老年代、元空间)
  6. GC前的对内存大小连续图(整堆、年轻代、老年代、元空间)
  7. GC回收垃圾连续图
  8. GC原因列表

6、OOM类型

  1. java heap space 堆内存溢出,根据dump快照分析可疑对象,定位代码进行解决
  2. Metaspace ①动态创建的类太多,利用jstack查看堆栈信息,定位代码。②空间设置过小,增加空间
  3. GC over head limit excepted 默认情况下,jvm用了98%的时间回收垃圾,回收效果不到%2,(内存泄漏、大对象或者长生命周期对象导致的)
  4. Direct Buffer Memory,①直接内存设置过小(-XX:MaxDirectMemorySize 默认64M) ②使用直接内存的时候没有释放
  5. unable to create new native thread,①查看堆栈,确定线程数,不多就查看系统允许的线程数,多就去查看什么线程创建过多,定位代码,分析解决
  6. request {} byte for {} out of swap 使用到了直接内存,分析是否内存泄漏,分析大对象或者长期存活对象,定位代码,进行解决

 

调优思维

  1. 首先不对JVM各区大小进行设置,使用默认值,开启GC日志,开启OOM的时候触发快照
  2. 运行一段时间,利用GCeasy分析GC日志,在正常运行的情况下,获取到FullGC后的老年代的大小(OldSizeAfterFullGC)
  3. 设置-Xms和-Xmx的大小为 3~4 倍 的 OldSizeAfterFullGC
  4. 设定-Xmn的大小为 1~1.5倍的 OldSizeAfterFullGC
  5. 设定-XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 大小为 FullGC后的元空间使用大小的 1.2~1.5倍
  6. 继续运行
  7. 分析日志,如果MinorGC过于频繁则增加 -Xmn的大小,如果MinorGC的间隔时间太长,则减少新生代的大小,具体测试决定

 

线上解决频繁FullGC问题

  1. 利用GCeasy分析GC日志
  2. 了解整体性能(吞吐量、GC延迟)
  3. 查看FullGC频率,确定是频繁FullGC
  4. 查看FullGC的原因,杜绝手动调用System.gc()
  5. 查看元空间在GC前后的占用空间的统计图,确定是否因为元空间被打满导致的频繁FullGC
  6. 查看整堆在GC后的占用空间统计图,看是否持续上涨,如果是是内存泄漏问题
  7. 查看垃圾回收数据量的统计图,确定是否回收了数据,如果回收了数据,但是堆数据还是持续上涨到最大值,考虑是死循环,使用top查看高CPU占用进程获取pid,使用top -Hp pid获取进程内高cpu占用的线程pid,printf "%x\n" pid 将线程pid转换为16进制,用jstack 去dump指定进程,根据线程pid找到数据,定位代码,进行分析
  8. 回收没有效果,dump堆内存,利用MAT工具进行分析,定义可疑大对象或者长期存活的对象,定位到代码,进行分析
posted @ 2022-03-22 18:06  甜菜波波  阅读(645)  评论(0编辑  收藏  举报