如何积累JVM问题分析与调优实战经验?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1640个文字,预计阅读时间需要7分钟。
一、前言+JVM性能优化步骤:+ 评估系统参数+压测后,调整JVM参数+线上系统监控和优化+统一的JVM参数模板+线上频繁Full GC的表现:+ 机器CPU负载过高+频率高
一、前言
JVM性能优化步骤:
线上频繁Full GC的表现:
- 机器CPU负载过高
- 频繁Full GC报警
- 系统无法处理请求或者处理过慢
频繁Full GC常见原因:
系统承载高并发请求,或处理数据量过大,导致Young GC频繁,每次Young GC过后存活对象太多,内存分配不合理,Survivor区域过小。
针对以上Full GC常见的原因,对应的优化方式:
一、案例一:高分配速率(High Allocation Rate)
分配速率(Allocation rate)表示单位时间内分配的内存量。
通常使用MB/sec作为单位。上一次垃圾收集之后, 与下一次GC开始之前的年轻代使用量, 两者的差值除以时间, 就是分配速率。分配速率过高就会严重影响程序的性能, 在JVM中可能会导致巨大的GC开销。
- 正常系统: 分配速率较低 ~ 回收速率 -> 健康
- 内存泄漏: 分配速率 持续大于 回收速率 ->OOM
- 性能劣化: 分配速率较高 ~ 回收速率 -> 亚健康
思考一个问题, 分配速率, 到底影响什么?
想一想,new出来的对象, 在什么地方。
答案就是,Eden。
假如我们增加Eden, 会怎么样。 考虑蓄水池效应。 最终的效果是, 影响Minor GC的次数和时间, 进而影响吞吐量。
在某些情况下, 只要增加年轻代的大小, 即可降低分配速率过高所造成的影响。
增加年轻代空间并不会降低分配速率, 但是会减少GC的频率。如果每次GC后只有少量对象存活,minor GC的暂停时间就不会明显增加。
二、案例二:过早提升(Premature Promotion)
提升速率(promotion rate)用于衡量单位时间内从年轻代提升到老年代的数据量。
一般使用MB/sec作为单位, 和分配速率类似。
JVM会将长时间存活的对象从年轻代提升到老年代。根据分代假设, 可能存在一种情况, 老年代中不仅有存活时间长的对象, 也可能有存活时间短的对象。
这就是过早提升: 对象存活时间还不够长的时候就被提升到了老年代。
major GC不是为频繁回收而设计的, 但major GC现在也要清理这些生命短暂的对象, 就会导致GC暂停时间过长。这会严重影响系统的吞吐量。
GC之前和之后的年轻代使用量以及堆内存使用量。
这样就可以通过差值算出老年代的使用量。
和分配速率一样, 提升速率也会影响GC暂停的频率。但分配速率主要影响minor GC, 而提升速率则影响major GC的频率。
有大量的对象提升, 自然很快将老年代填满。老年代填充的越快, 则major GC事件的频率就会越高。
一般来说过早提升的症状表现为以下形式:
要演示这种情况稍微有点麻烦, 所以我们使用特殊手段, 让对象提升到老年代的年龄比默认情况小很多。 指定GC参数-Xmx24m -XX:NewSize=16m -XX:MaxTenuringThreshold=1, 运行程序之后, 可以看到下面的GC日志:
解决这类问题, 需要让年轻代存放得下暂存的数据, 有两种简单的方法:
但总体目标依然是一致的: 让临时数据能够在年轻代存放得下。
本文共计1640个文字,预计阅读时间需要7分钟。
一、前言+JVM性能优化步骤:+ 评估系统参数+压测后,调整JVM参数+线上系统监控和优化+统一的JVM参数模板+线上频繁Full GC的表现:+ 机器CPU负载过高+频率高
一、前言
JVM性能优化步骤:
线上频繁Full GC的表现:
- 机器CPU负载过高
- 频繁Full GC报警
- 系统无法处理请求或者处理过慢
频繁Full GC常见原因:
系统承载高并发请求,或处理数据量过大,导致Young GC频繁,每次Young GC过后存活对象太多,内存分配不合理,Survivor区域过小。
针对以上Full GC常见的原因,对应的优化方式:
一、案例一:高分配速率(High Allocation Rate)
分配速率(Allocation rate)表示单位时间内分配的内存量。
通常使用MB/sec作为单位。上一次垃圾收集之后, 与下一次GC开始之前的年轻代使用量, 两者的差值除以时间, 就是分配速率。分配速率过高就会严重影响程序的性能, 在JVM中可能会导致巨大的GC开销。
- 正常系统: 分配速率较低 ~ 回收速率 -> 健康
- 内存泄漏: 分配速率 持续大于 回收速率 ->OOM
- 性能劣化: 分配速率较高 ~ 回收速率 -> 亚健康
思考一个问题, 分配速率, 到底影响什么?
想一想,new出来的对象, 在什么地方。
答案就是,Eden。
假如我们增加Eden, 会怎么样。 考虑蓄水池效应。 最终的效果是, 影响Minor GC的次数和时间, 进而影响吞吐量。
在某些情况下, 只要增加年轻代的大小, 即可降低分配速率过高所造成的影响。
增加年轻代空间并不会降低分配速率, 但是会减少GC的频率。如果每次GC后只有少量对象存活,minor GC的暂停时间就不会明显增加。
二、案例二:过早提升(Premature Promotion)
提升速率(promotion rate)用于衡量单位时间内从年轻代提升到老年代的数据量。
一般使用MB/sec作为单位, 和分配速率类似。
JVM会将长时间存活的对象从年轻代提升到老年代。根据分代假设, 可能存在一种情况, 老年代中不仅有存活时间长的对象, 也可能有存活时间短的对象。
这就是过早提升: 对象存活时间还不够长的时候就被提升到了老年代。
major GC不是为频繁回收而设计的, 但major GC现在也要清理这些生命短暂的对象, 就会导致GC暂停时间过长。这会严重影响系统的吞吐量。
GC之前和之后的年轻代使用量以及堆内存使用量。
这样就可以通过差值算出老年代的使用量。
和分配速率一样, 提升速率也会影响GC暂停的频率。但分配速率主要影响minor GC, 而提升速率则影响major GC的频率。
有大量的对象提升, 自然很快将老年代填满。老年代填充的越快, 则major GC事件的频率就会越高。
一般来说过早提升的症状表现为以下形式:
要演示这种情况稍微有点麻烦, 所以我们使用特殊手段, 让对象提升到老年代的年龄比默认情况小很多。 指定GC参数-Xmx24m -XX:NewSize=16m -XX:MaxTenuringThreshold=1, 运行程序之后, 可以看到下面的GC日志:
解决这类问题, 需要让年轻代存放得下暂存的数据, 有两种简单的方法:
但总体目标依然是一致的: 让临时数据能够在年轻代存放得下。

