基础概念
定义: Garbage First,垃圾优先,主要面向服务端应用的垃圾收集器。
开启命令: -XX:+UseG1GC
目标: “停顿时间模型”的收集器:能够支持指定所在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间大概率不超过N毫秒这样的目标。
适用场景: 适用于大内存、多CPU的机器。
设计理念
跳出之前要不收集新生代,要不收集老年代的樊笼,G1面向所有的堆内存任何部分来组成回收集进行回收,衡量标准不再是它属于哪个分代,而是哪块区域中存放的垃圾数量最多,回收效益最大。
区域划分
Region区域
定义: 将Java堆划分为多个大小相等的Region,每个Region都可以是新生代、老年代。G1收集器根据角色的不同采用不同的策略去处理
大小: 2 的N次幂,1MB~32MB
配置参数: -XX:G1HeapRegionSize,不指定G1会根据堆大小自行指定
Humongous区域(Region中的一部分)
定义: 专门用来存储大对象(超过Region容量一半的对象即为大对象),超过整个Region区域的会放在多个连续的Humongous区。
回收身份: G1把Humongous当做老年代的一部分
垃圾收集
借助R大的回答,从最高层看,G1的Collector一侧就是两个大部分,并且这两个部分可以相对独立执行。
- 全局并发标记(global concurrent marking)
- 拷贝存活对象(evacuation)
全局并发标记(global concurrent marking)
基于SATB(Snapshot At The Begining)形式的并发标记。
1、初始标记(STW)
G1对根进行标记。扫描根集合,标记所有从根集合可直接到达的对象(CMS的初始标记也是类似)并将它们的字段压入扫描栈(marking stack)中等到后续扫描。G1使用外部的bitmap来记录mark信息,而不是用对象头的mark word里的mark bit。在分代式G1模式中,初始标记阶段借用 yong GC的暂停,因而没有额外的、单独的暂停阶段。
为什么初始标记阶段是借用Yong GC的暂停做的?
从逻辑上将“全局并发标记”和“拷贝存活对象”是相对独立的,但是“全局并发标记”阶段的“初始标记”阶段又和Yong GC要做的事情有重叠---遍历根集合,所以在实现上把他们安排在一起做,Yong GC期间可以顺带做,也可以不做。
2、并发标记
G1在整个堆中查找可以访问的(存活的)对象,递归扫描整个堆里的对象图。每扫描到一个对象就对其进行标记,并压入扫描栈中。重复扫描过程直到扫描栈清空。过程中还会扫描SATB 写屏障(write barrier)所记录下的引用,SATB相关下文会介绍。
3、最终/重新标记(STW)
处理在并发标记阶段剩余未处理的SATB写屏障的记录。同时此阶段也进行弱引用处理(reference proccessing),**这个暂停与CMS的remark有一个本质的区别,这个暂停只需要扫描SATB buffer(将这些旧引用作为根重新扫描一遍