5.1 调优领域
- 内存
- 锁竞争
- cpu占用
- io
5.2 确定目标(垃圾回收阶段)
- 【低延迟】还是【高吞吐量】,选择合适的回收器
* 互联网项目追求的是低延迟 - CMS,G1,ZGC:响应时间优先的垃圾回收器
- ParallelGC:高吞吐量垃圾回收器
- Zing
5.3 最快的GC是不发生GC
5.4 新生代调优
- TLAB (Thread Local Allocation Buffer,线程本地分配缓冲区)是 Java 中内存分配的一个概念,它是在 Java 堆中划分出来的针对每个线程的内存区域,专门在该区域为该线程创建的对象分配内存。它的主要目的是在多线程并发环境下需要进行内存分配的时候,减少线程之间对于内存分配区域的竞争,加速内存分配的速度。
5.4.1新生代调优方法
- 新生代内存越大越好?
- 设置小,不太好,可用空间小,空间不足时,会执行mirro GC,会有短暂的STW
- 设置大了,老年代的可用空间小,老年代存的少,会执行Full GC,STW时间更长
Oracle中的建议新生代比例1/4-1/2之间
理想情况:
- 新生代能容纳【并发量*(请求-响应)】的数据
- 幸存区达到能保留【当前活跃对象+需要晋升对象】
* 当前活跃对象:生命周期较短,下次有可能被回收
* 需要晋升对象:将来肯定晋升的老年代
如果过小的话,本来会继续存储在幸存区中,此时会被晋升至老年代,增加老年代垃圾回收时间
如果不晋升至老年代,会在新生代的幸存区进行来回复制,会降低性能。因为:新生代复制算法,主要的耗时在于复制上
5.5 老生代调优
一般75%-80%:浮动垃圾占比20-25%
5.6 案例
-
案例1:Full GC和MinorGC频繁
-
原因分析:空间紧张,如果当新生代内存较小,业务繁多,会将新生代塞满。幸存区空间紧张,导致晋升的阈值减少
导致本来不改晋升的对象,晋升至老年代,老年代中存放着生命周期短的对象,会加速老年代内存塞满,导致老年代的FullGC频繁- 解决方法:内存优化先从新生代开始,先增大新生代内存,同时增大的S区的内存,和晋升的阈值。
-
案例2:请求高峰期发生FullGC,单次暂停时间特别长(CMS)
原因分析:CMS中,初始标记和并发标记的时间都是很快,而重新标记的时间会很难,因为重新标记时,会扫描整个内存,新生代和老年代都会扫描。如果业务多,老年代会引用新生代,遍历算法会耗时很多。
解决方法:在重新标记之前,对新生代进行垃圾回收,设置参数CMSScavengeBeforeRemark。
-
-
案例3:老年代充裕情况下,发生Full GC(CMS jak1.7)