天天看点

JVM调优实战演练,妈妈再也不同担心我的性能优化了

大家好呀,我是狂野君,这篇文章是JVM性能调优的最后一篇了,也是非常重要的实战篇

俗话说的好,光说不练,假把式

这篇实战篇就带大家一起动手练练

7、调优实战

7.1 环境

  • 我们依然使用上面收集器章节相同的案例,这次针对内存来做详细分析。
  • 使用企业里主流的jdk8运行,其他jdk版本参数可能略有不同。
  • jdk自带的分析命令和工具给大家准备了扩展资料
  • 这里我们使用在线、简洁、高效的图形化分析工具:​​gceasy.io​​
  • gc日志参数:
XX:+PrintGC 输出GC日志
 -XX:+PrintGCDetails 输出GC的详细日志
 -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
 -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
 -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
 -Xloggc:gc.log   jdk8日志文件的输出
 
 -Xlog:gc*:gc.log  jdk11日志输出方式略有不同      

7.2 初始状态

7.2.1 参数

XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log      
JVM调优实战演练,妈妈再也不同担心我的性能优化了

7.2.2 执行日志

运行一段时间后,在项目的目录下会看到gc.log

7.2.3 日志分析

打开 gceasy 的主页,上传后点击 Analyze 即可看到分析结果

JVM调优实战演练,妈妈再也不同担心我的性能优化了

1)整体内存概况

young与old全部吃满,均明显不足,需要调大,meta闲置,可以缩减

JVM调优实战演练,妈妈再也不同担心我的性能优化了

2)整体时间情况

收集时间绝大多数在10ms以内,说明收集的速度还可以,但是回收次数明显偏多,整体吞吐量94

3)回收前后的heap明显抖动频繁,整体偏高

4)GC间隔时间长的点,发生大量FullGC

5)大批量空间的有效释放在FullGC上

6)回收释放情况

年轻代和年老代回收效果一般,回收前后的两条线甚至发生交叉,应该偏离较远才说明有明显内存下降

Metaspace比较稳定

7)A&P:对象从年轻代晋升到老年代的情况

频繁晋升,跨代移动,说明年轻代不够用,老年代一旦堆积,极容易引发fullGC

JVM调优实战演练,妈妈再也不同担心我的性能优化了

8)GC次数及时间统计

发生591次GC,里面竟然有45是FullGC,不可容忍!

总GC耗时,2.820s,FullGC占了将近一半

9)GC停顿情况

总耗时、平均每次GC耗时 4.77ms

10)GC被触发的原因

常规达到阈值垃圾回收45次。

内存分配失败引发回收,这个会影响正常业务执行。

JVM调优实战演练,妈妈再也不同担心我的性能优化了

7.3 初步调优

7.3.1 参数

分析上面的情况,明显年轻代老年代内存均严重不足,那么最简单粗暴的方式,我们加大内存

XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log      

7.3.2 二次分析

重复上面的步骤,新开一个浏览器页签,方便对比分析日志,重点关注几个点:

1)总内存够用了,但是年轻代依然被吃爆。年老代闲置。

JVM调优实战演练,妈妈再也不同担心我的性能优化了

2)吞吐量上升,耗时特别长的gc分部区间明显减少,甚至消失

JVM调优实战演练,妈妈再也不同担心我的性能优化了

3)gc前后的空间曲线对比明显

JVM调优实战演练,妈妈再也不同担心我的性能优化了

4)FullGC消失!

JVM调优实战演练,妈妈再也不同担心我的性能优化了

5)GC大批量的内存释放发生在了年轻代

JVM调优实战演练,妈妈再也不同担心我的性能优化了

6)年轻代的回收前后两条曲线不再交叉,被明显剥离

JVM调优实战演练,妈妈再也不同担心我的性能优化了

7)年老代表示情绪稳定

JVM调优实战演练,妈妈再也不同担心我的性能优化了

8)年轻到老年代的晋升明显减少

JVM调优实战演练,妈妈再也不同担心我的性能优化了

9)FullGC完全消失,总GC次数明显减少到49,总停顿时间从上次的2.8s降低到0.3s

JVM调优实战演练,妈妈再也不同担心我的性能优化了

10)晋升的对象明显减少,创建速度提升

JVM调优实战演练,妈妈再也不同担心我的性能优化了

11)不再发生内存分配失败造成gc的现象

JVM调优实战演练,妈妈再也不同担心我的性能优化了

7.4 二次调优

7.4.1 参数

结合上次调优,我们发现,年轻代依然不够用,年老代闲置,对象还是会频繁从年轻代晋升到年老代。

结合我们的业务场景,大批量对象在请求后会被释放,属于短生命周期。包括我们现实中从数据库请求发送到网页后对象就完成了实名,属于同类场景。

所以,加大年轻代比例!

XX:NewSize=250m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log      

7.4.2 日志分析

同样是256的内存,我们再次跑出日志分析看看差异

1)年轻代已基本够用,很少有对象再跑到老年代

JVM调优实战演练,妈妈再也不同担心我的性能优化了

2)吞吐量进一步上升

JVM调优实战演练,妈妈再也不同担心我的性能优化了

思考一下,那为什么pause的平均时间还变长了呢???

答:次数变少了,单次需要收集的对象多了,所以肯定要占时间,我们接着往下看总耗时!

3)堆回收空间变化明显

JVM调优实战演练,妈妈再也不同担心我的性能优化了

4)gc次数明显下降到8次,总时间进一步降低到80ms

JVM调优实战演练,妈妈再也不同担心我的性能优化了

7.5 小结

  • 机器主要用来跑java服务的话,一般是需要调优的。因为默认堆最大只占物理内存的1/4
  • jvm的调优没有标准可言,不同业务场景的内存占用和增长情况不同。调整需要根据结果一步步来,直到最优。
  • 调优工具很多,gceasy属于简单直观的ui操作,jvm自带工具大多是命令行且功能较少,在扩展资料里。
  • parallel是jdk8下的默认收集器,切换不同收集器后的调试与上面过程一致,感兴趣的同学可以逐个尝试。