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性能的影响 。
注意:对象进入老年代的几种方式:
  1. 大对象
  2. 对象到达一定年龄阈值
  3. 动态对象年龄判断(Young GC后的存活对象小于Survivor区域的50%)
调优案例案例准备这里准备了一个示例程序(demo链接) , 运行以后,我们采用上篇文章介绍到的jstat工具查看各个内存gc的情况 。
初始JVM参数:
-Xms1536M -Xmx1536M -Xmn512M -Xss256K -XX:SurvivorRatio=6 -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly根据这些参数,我们知道大体的内存模型是这样的:最快经过6s之后才会发生一次Young GC 。
jvm调优思路及调优案例

文章插图
调优分析【jvm调优思路及调优案例】示例程序启动后,我们调用测试类的test()方法:
@RunWith(SpringRunner.class)@SpringBootTest(classes={Application.class})// 指定启动类public class ApplicationTests { @Bean public RestTemplate restTemplate() {return new RestTemplate(); } @Autowired private RestTemplate restTemplate; @Test public void test() throws Exception {for (int i = 0; i < 10000; i++) {String result = restTemplate.getForObject("http://localhost:8080/user/process", String.class);Thread.sleep(1000);} }}然后观察整个过程前后,虚拟机的内存gc变化:
jvm调优思路及调优案例

文章插图
发现不仅Young GC次数增多了,Full GC的次数也随着增多,说明对象不仅增长得快,连进入老年代的时间挺快的 。

推荐阅读