jvm调优思路及调优案例

jvm调优思路及调优案例我们说jvm调优 , 其实就是不断测试调整jvm的运行参数 , 尽可能让对象都在新生代(Eden)里分配和回收 , 尽量别让太多对象频繁进入老年代 , 避免频繁对老年代进行垃圾回收 , 同时给系统充足的内存大小 , 避免新生代频繁的进行垃圾回收 。从而减少STW(stop the world)的时间 。
调优思路项目运行内存分析我们运行应用程序时 , 一般会设置一些jvm参数 , 比如堆内存大小 , 年轻代大小 , Eden和Survivor的比例 , 老年代大小 , 大对象的阈值 , 大龄对象进入老年代的阈值等 。
而设置这些jvm参数 , 有2种方式:

  1. 通过物理内存分析设置 , 比如机器有8G内存 , 假设操作系统分配2-3G , 元空间分配256M , 堆分配4-5G 。
  2. 通过1设置之后 , 再通过分析具体的gc日志来调优 。
我们知道jvm有自己的运行时数据区(内存模型) , 其中堆大小 , 以及堆中的年轻代、老年代的大小比例至关重要 , 主要就是调整堆中的内存比例 , 运行时数据区(内存模型)图 , 如下图:
jvm调优思路及调优案例

文章插图
具体思路1、分析年轻代对象增长的速率
可以执行命令 jstat -gc pid 1000 10 (每隔1秒执行1次命令 , 共执行10次) , 通过观察EU(eden区的使用)来估算每秒eden大概新增多少对象 , 如果系统负载不高 , 可以把频率1秒换成1分钟 , 甚至10分钟来观察整体情况 。注意 , 一般系统可能有高峰期和日常期 , 所以需要在不同的时间分别估算不同情况下对象增长速率 。
2、Young GC的触发频率和每次耗时
知道年轻代对象增长速率我们就能推根据eden区的大小推算出Young GC大概多久触发一次 , Young GC的平均耗时可以通过 YGCT/YGC 公式算出 , 根据结果我们大概就能知道系统大概多久会因为Young GC的执行而卡顿多久 。
3、每次Young GC后有多少对象存活和进入老年代
这个因为之前已经大概知道Young GC的频率 , 假设是每5分钟一次 , 那么可以执行命令 jstat -gc pid 300000 10  , 观察每次结果eden , survivor和老年代使用的变化情况 , 在每次gc后eden区使用一般会大幅减少 , survivor和老年代都有可能增长 , 这些增长的对象就是每次Young GC后存活的对象 , 同时还可以看出每次Young GC后进去老年代大概多少对象 , 从而可以推算出老年代对象增长速率 。
4、Full GC的触发频率和每次耗时
知道了老年代对象的增长速率就可以推算出Full GC的触发频率了 , Full GC的每次耗时可以用公式 FGCT/FGC 计算得出 。
总结:尽量让每次Young GC后的存活对象小于Survivor区域的50% , 都留存在年轻代里 。尽量别让对象进入老年代 。尽量减少Full GC的频率 , 避免频繁Full GC对JVM性能的影响 。
【jvm调优思路及调优案例】注意:对象进入老年代的几种方式:
  1. 大对象
  2. 对象到达一定年龄阈值
  3. 动态对象年龄判断(Young GC后的存活对象小于Survivor区域的50%)
调优案例案例准备这里准备了一个示例程序(demo链接) , 运行以后 , 我们采用上篇文章介绍到的jstat工具查看各个内存gc的情况 。

经验总结扩展阅读