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

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

大家好呀,我是狂野君,这篇文章是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 参数

 -Xmx32m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log
复制代码

image.png

7.2.2 执行日志

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

image.png

7.2.3 日志分析

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

image.png

1)整体内存概况

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

image.png

2)整体时间情况

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

image.png

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

image.png

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

image.png

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

image.png

6)回收释放情况

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

Metaspace比较稳定

image.png

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

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

image.png

8)GC次数及时间统计

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

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

image.png

9)GC停顿情况

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

image.png

10)GC被触发的原因

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

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

image.png

7.3 初步调优

7.3.1 参数

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

 -Xms256m -Xmx256m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log
复制代码

7.3.2 二次分析

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

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

image.png

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

image.png

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

image.png

4)FullGC消失!

image.png

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

image.png

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

image.png

7)年老代表示情绪稳定

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

image.png

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

image.png

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

image.png

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

image.png

7.4 二次调优

7.4.1 参数

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

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

所以,加大年轻代比例!

 -Xms256m -Xmx256m -XX:NewSize=250m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:gc.log
复制代码

7.4.2 日志分析

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

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

image.png

2)吞吐量进一步上升

image.png

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

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

3)堆回收空间变化明显

image.png

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

image.png

7.5 小结

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

好了,今天的JVM调优实战相关的内容就到这里了,我们下期再见 如果大家觉得有帮助,欢迎点赞、收藏,您的认可是我们最大的动力。

下面是JVM调优的系列文章,希望对大家能够有所帮助。

往期干货:

  1. 怎样才能快速成为一名架构师?
  2. 【图文并茂】这次一文讲透JVM架构、类文件结构、字节码结构!!)
  3. 4859字,609行,一次讲清楚JVM运行数据区 )
  4. 搞不懂JVM的类加载机制,JVM性能优化从何谈起? )
  5. 当你new了一个对象时,JVM底层都帮你干了啥? )
  6. 13651个字,给你解释清楚 JVM对象销毁 )

猜你喜欢

转载自juejin.im/post/7103414151061438477