GC调优
- 一、新生代调优
- 二、幸存区调优
- 三、老年代调优
- 四、GC调优案例
- 案例一:Full GC和Minor GC频繁
- 案例二:请求高峰期发生Full GC,单次暂停时间特别长(CMS)
- 案例三:老年代充裕情况下,发生Full GC(CMS 1.7)
预备知识
● 掌握GC相关的JVM参数,会基本的空间调整
● 掌握相关工具
● 明白一点:调优跟应用、环境有关,没有放之四海而皆准的法则(具体到实际应用需要根据实际情况进行调整)
JVM参数可通过oracle官网查看也可通过命令查看当前环境下虚拟机运行参数:
"D:\Java\jdk1.8\bin\java" -XX:+PrintFlagsFinal -version | findstr "GC"
( findstr “GC”===>找到与GC相关的参数)
调优领域
● 内存
● 锁竞争
● CPU占用
● IO
● GC
垃圾回收的调优仅仅是众多调优其中的一个方向,若要使应用程序的性能有全面的提升需从各个领域深入分析进而调优
确定目标
低延迟/高吞吐量? 选择合适的GC
● CMS G1 ZGC
● ParallelGC
● Zing
最快的GC是不发生GC
首先排除减少因为自身编写的代码而引发的内存问题
● 查看Full GC前后的内存占用,考虑以下几个问题
① 数据是不是太多?
② 数据表示是否太臃肿?
——对象图
——对象大小
③ 是否存在内存泄漏?
一、新生代调优
● 新生代的特点
① 所有的new操作分配内存都是非常廉价的
————TLAB
② 死亡对象回收零代价
③ 大部分对象用过即死(朝生夕死)
④ MInor GC 所用时间远小于Full GC
TLAB===>thread-local allocation buffer 【每个线程都会在伊甸园中分配一块私有区域TLAB),当new一个对象时首先会检查TLAB缓冲区中有无可用内存,若有,则优先会在此区域进行对象分配;为什么会如此分配?===>对象分配也存在线程安全的问题,例如线程1在分配内存还未结束过程中线程2不能也来分配这块内存,否则会造成内存分配混乱,因此在做对象的内存分配时,也要做线程并发安全的保护,这个过程是由JVM来实现的===>TLAB会让每个线程用自己私有的伊甸园内存来进行分配(此时即使多个线程同时创建对象也不会产生内存占用干扰)】
● 增大新生代内存是新生代调优的最有效方式。那么新生代内存越大越好么?
oracle官方建议:young generation greater than 25% and less than 50% of the overall heap size
===>大于堆的25%以上小于堆的50%
不是
——新生代内存太小:频繁触发Minor GC,会STW,会使得吞吐量下降
——新生代内存太大:老年代内存占比有所降低,会更频繁地触发Full GC。而且触发Minor GC时,清理新生代所花费的时间会更长
新生代内存设置为能容纳所有 [并发量*(请求——响应)] 的数据为宜
为什么设置为并发量并发量*(请求——响应)可称为理想状态?
一次请求响应的过程以后其中大部分对象都会被回收,而只要一次请求+并发量占用的内存不超过新生代内存就不会触发或较少触发新生代的垃圾回收
二、幸存区调优
● 幸存区大到能够保存 【当前活跃对象+需要晋升的对象】
● 晋升阈值配置得当,让长时间存活的对象尽快晋升
-XX:MaxTenuringThreshold=threshold
-XX:+PrintTenuringDistribution
三、老年代调优
以CMS为例
● CMS的老年代内存越大越好(预留更多空间,避免浮动垃圾引起的并发失败)
● 先尝试不做调优,如果没有Full GC则说明老年代空间很充裕,否则先尝试调优新生代
● 观察发生Full GC时老年代内存占用,将老年代内存预设调大1/4~1/3
—— -XX:CMSInitiatingOccupancyFraction=percent
【老年代空间占用达到老年代总内存多少时使用CMS进行垃圾回收】
浮动垃圾
:垃圾回收的同时其他用户线程也在运行就会产生新的垃圾,这些新的垃圾称为浮动垃圾
四、GC调优案例
案例一:Full GC和Minor GC频繁
GC频繁说明空间紧张,若是新生代的空间紧张,当业务高峰期时大量对象被创建将新生代的空间很快占满,这时幸存区空间紧张使对象晋升预值降低,导致很多本来生存周期很短的对象也会被晋升到老年代,进一步触发老年代Full GC 的频繁发生
案例二:请求高峰期发生Full GC,单次暂停时间特别长(CMS)
CMS垃圾回收器在初始及并发标记耗时较短,而重新标记阶段较慢(CMS在重新标记时需要扫描整个堆内存)。使用-XX:+CMScavengeBeforeRemark
调优参数在重新标记发生之前先对新生代的对象做一次垃圾清理,清理之后存活对象即可减少,此时重新标记时需要标记和查找的对象也随之减少
案例三:老年代充裕情况下,发生Full GC(CMS 1.7)
由于永久代内存不足导致(1.7以前永久代内存不足会触发整个堆的Full GC)