G1收集器
在JDK9之后JVM默认使用G1(Garbage-First, 垃圾优先)收集器进行垃圾回收。G1是一款分代的 (generational),增量的 (incremental),并行的 (parallel),移动式(evacuating)的,软实时的垃圾回收器。其最大特点是用Region代替传统分代模型,分代成为逻辑上的概念;建立了可预测的停顿时间模型,让暂停时间可配置。从实践结果来看,它能及时有效的回收大对象,增加吞吐量,避免内存碎片,保障程序的长久运行。
一、内存模型对比
传统的垃圾收集器(串行、并行、CMS)都将堆结构分为三个部分:年轻代、老年代和固定内存大小的永久代
- 传统收集器内存结构
G1中的堆被划分为N个Region,每个region内内存连续,其中一部分被分配为传统的角色(eden、survivor、old),但它们不是固定的位置和大小,这给内存分配提供了极大的灵活性。
- G1内存结构
二、GC步骤
G1中有两种回收模式:
- 年轻代垃圾回收(Young GC)
- 混合垃圾回收(Mixed GC)
2.1 年轻代GC
年轻代GC是只选择年轻代区域(Eden/Survivor)进入回收集合(Collection Set,简称CSet)进行回收的模式。年轻代GC的过程和其他的分代回收器差不多,新创建的对象分配至Eden区域,然后将标记存活的对象移动至Survivor区,达到晋升年龄的就晋升到老年代区域,然后清空原区域(不过这里可没有年轻代复制算法中两个Survivor的交换过程)。
- G1在遵循GC暂停时间的基础上,选择最大年轻代Region数(CSSet)
- 根扫描(Root Scanning)
- RememberedSet扫描(RememberedSet简称RSet,会记录跨代引用的关系)
- 移动,遍历上面的标记栈,将栈内的所有所有的对象移动(复制)至Survivor区域
年轻代GC图示:
2.2 混合GC
混合GC会选择所有年轻代区域(Eden/Survivor,最大年轻代分区数)和部分老年代区域进去回收集合进行回收的模式。年轻代区域对象移动到Survivor区,老年代区域移动到老年代区域。
初始标记
这个是捎带在年轻代GC完成的
并发标记
并发标记的目的是标记存活对象,为移动过程做准备。在并发标记阶段,若发现区域对象中的所有对象都是垃圾,那这个区域会被立即回收。
再次标记
由于应用程序持续进行,需要修正上一次的标记结果。G1中采用了比CMS更快的初始快照算法:snapshot一at一the一beginning (SATB)。此时,所有区域的活性都被计算出来了。
复制清理阶段
G1 选择“活跃度”最低的区域,即可以收集最快的区域。然后与年轻的GC同时收集这些区域
最终清理阶段
所选择的区域都被复制,然后压缩
混合GC总结
阶段 | 是否STW | 描述 |
---|---|---|
初始标记 | 是 | 捎带在年轻代GC完成 |
根区域扫描 | 否 | 扫描幸存者区域以查找对老年代的引用 |
并行标记 | 否 | 查找整个堆上的活动对象 |
再次标记 | 是 | 遗漏的再标记一次 |
清理 | 是 | 对活动对象和完全自由区域执行记帐;擦洗RSet;重置空区域并将其返回到可用列表 |
复制 | 是 | 疏散或复制活动对象到未使用区域 |
三、GC日志
G1 GC的垃圾回收过程主要包括如下三个环节:
年轻代GC (Young GC)、老年代并发标记过程 (Concurrent Marking)、混合回收(Mixed GC)。并发标记是全局的,和回收过程是两个阶段。
年轻代GC日志
1 | //[GC pause (G1 Evacuation Pause) (young) 代表完全年轻代回收 |
并发标记日志
1 | //并发标记 - 初始标记阶段,在年轻代GC中完成 |
混合GC日志
1 | // 混合回收Mixed GC其实和YGC的日志类似,能看到GC pause(G1EvacuationPause)(mixed)这样的信息 |
四、GC算法
算法 | 分代 | 优缺点 |
---|---|---|
标记清除(Mark-Sweep) | 年轻代 | 效率低,产生内存碎片 |
复制(Copying) | 老年代 | 效率高,空间利用率低 |
标记压缩(Mark-Compact) | 老年代 | 针对老年代对象特征优化 |
分代收集 | 年轻代使用复制,老年代使用标记压缩 | |
4.1 标记清除
4.2 复制算法
4.3 标记压缩
五、参数设置
参数 | 含义 |
---|---|
-XX:+UseG1GC | JDK8需要设置 |
-XX:G1HeapRegionSize | 设置每个Region的大小。值是2的幂,范围是1MB到32MB之间 |
-XX:MaxGCPauseMillis | 期望达到的最大GC停顿时间指标,默认200ms |
-XX:ParallelGCThread: | 垃圾回收线程,最多为8,STW时 |
-XX:ConcGCThreads | 并发标记线程数,一般=ParallelGCThreads/4 |
参数设置参考
由于是传统ERP项目,存量业务和大对象很多,所以Xmx设置的也比较大:
1 | -Xms6g -Xmx12g -XX:+UseG1GC -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -Xss512k -XX:MetaspaceSize=768m -XX:MaxMetaspaceSize=2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/log/erp-%t.hprof -XX:MaxDirectMemorySize=256m -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:/data/log/erp-gc-%t.log |
参考
G1垃圾回收期入门
https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html
G1详解
https://juejin.cn/post/7010034105165299725
最清晰易懂的G1
https://segmentfault.com/a/1190000039411521