一、垃圾回收器种类
1. 串行
- 单线程
- 堆内存较小,适合个人电脑
使用参数:-XX:+UseSerialGC(复制算法) = Serial + SerialOld(标记整理算法)
工作过程:

2. 吞吐量优先
- 多线程
- 堆内存较大,多核 cpu
- 让单位时间内,STW 的时间最短 0.2 0.2 = 0.4,垃圾回收时间占比最低,这样就称吞吐量高
使用参数:-XX:+UseParallelGC ~ -XX:+UseParallelOldGC (jdk1.8默认使用的垃圾回收期)
-XX:ParallelGCThreads=n:并发垃圾回收线程数量,默认与cpu核实相同
-XX:+UseAdaptiveSizePolicy:动态分配新生代Eden与s0、s1分配比例
-XX:GCTimeRatio=ratio:调整垃圾回收时间与工作总时间占比,比值为1/(1+ratio),ratio越大,垃圾回收频率越小,默认99,一般设为19
-XX:MaxGCPauseMillis=ms:GC最大暂停毫秒数,默认200,与上述参数对立
工作过程:

3. 响应时间优先(CMS jdk 1.9废弃)
- 多线程
- 堆内存较大,多核 cpu
- 尽可能让单次 STW 的时间最短 0.1 0.1 0.1 0.1 0.1 = 0.5
使用参数-XX:+UseConcMarkSweepGC(标记清除算法) ~ -XX:+UseParNewGC ~ SerialOld 老年代当内存碎片过多,内存不足造成并发失败会退化使用串行垃圾回收器
-XX:ParallelGCThreads=n(并行线程数,包含用户线程与垃圾回收线程) ~ -XX:ConcGCThreads=threads(用于垃圾回收的并发线程,一般为ParallelGCThreads的1/4)
-XX:CMSInitiatingOccupancyFraction=percent 垃圾回收时的内存占比,用于垃圾回收时产生的浮动垃圾的回收
-XX:+CMSScavengeBeforeRemark 重新标记前对新生代做一次垃圾回收

二、G1垃圾回收器
三、垃圾回收调优
1、调优领域
内存、锁竞争、cpu 占用、io
2、确定目标(【低延迟】还是【高吞吐量】,选择合适的回收器)
CMS,G1,ZGC(低延迟)
ParallelGC(高吞吐量)
Zing(jdk12推出试用版回收器)
3、最快的 GC(答案是不发生 GC)
查看 FullGC 前后的内存占用,考虑下面几个问题
数据是不是太多?resultSet = statement.executeQuery("select * from 大表 limit n")
数据表示是否太臃肿?对象图、对象大小 16 Integer 24 int 4
是否存在内存泄漏?static Map map = ? 软引用、弱引用、第三方缓存实现
4、新生代调优
新生代的特点
- 所有的 new 操作的内存分配非常廉价 (TLAB thread-local allocation buffer)
- 死亡对象的回收代价是零
- 大部分对象用过即死
- Minor GC 的时间远远低于 Full GC
越大越好吗?
- 新生代能容纳所有【并发量 * (请求-响应)】的数据
- 幸存区大到能保留【当前活跃对象+需要晋升对象】
- 晋升阈值配置得当,让长时间存活对象尽快晋升
-XX:MaxTenuringThreshold=threshold(晋升阈值设置,默认15)
-XX:+PrintTenuringDistribution(晋升阈值打印)
Desired survivor size 48286924 bytes, new threshold 10 (max 10)
- age 1: 28992024 bytes, 28992024 total
- age 2: 1366864 bytes, 30358888 total
- age 3: 1425912 bytes, 31784800 total
5、老年代调优
以 CMS 为例
- CMS 的老年代内存越大越好(否则产生浮动垃圾,导致回退到串行垃圾回收器,效率较低)
- 先尝试不做调优,如果没有 Full GC 那么已经...,否则先尝试调优新生代
- 观察发生 Full GC 时老年代内存占用,将老年代内存预设调大 1/4 ~ 1/3
- -XX:CMSInitiatingOccupancyFraction=percent 老年代触发垃圾回收内存百分比