G1垃圾收集器
Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与 CMS 收集器, G1 收集器两个最突出的改进是:
- 基于标记-整理算法,不产生内存碎片。
- 可以非常精确控制停顿时间,在
不牺牲吞吐量
前提下,实现低停顿
垃圾回收。
G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域(Region),并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间, 优先回收垃圾最多的区域。区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率。
G1垃圾回收阶段
G1垃圾收集器分为三个阶段:Young Collection、Young Collection + Concurrent Marking、Mixed Collection。
也可分为:初始标记、并发标记、最终标记、筛选回收,四个阶段。和CMS垃圾收集过程很类似。
Young Collection
新生代垃圾回收阶段。会 stop the world。
前面说过,G1垃圾收集器会把堆内存划分为大小固定的几个独立区域(Region),每个区域可以是新生代的Eden、Survivor或老年代(Old)区域。
以下图中新生代Eden用E表示,Survivor用S表示,Old用O表示。
当触发新生代垃圾回收时,会将存活的 Eden 区域复制到 Survivor 区。
当年龄达到阈值,或者新生代内存不足时,会将部分对象晋升至老年代。
Young Collection + Concurrent Marking
新生代垃圾回收及并发标记阶段。
在新生代GC(Young Collection)时会进行GC Root的初始标记。
当老年代占用的空间达到一定阈值时会进行并发标记
,不会STW(stop the world)。
可通过JVM参数:
-XX:InitiatingHeapOccupancyPercent=45
,指定阈值为45%,默认也为45%。
Mixed Collection
混合收集阶段。会对 E、S、O 区域进行全面的垃圾回收。
经过了最终标记:
其中虚线区域代表需要进行垃圾回收的区域,即经过标记发现与GC Root之间不可达的区域。
由于G1垃圾收集器既注重吞吐量,又注重低时延的特性,设置了停顿时间
,所以在回收老年代时,如果停顿时间不够会回收价值比较大的老年代区域,所谓价值比较大即回收后能够释放更大的空间。图中粉色区域即为回收价值较大区域。
这一阶段会将垃圾回收价值较大老年代区域通过复制算法复制到存活的老年代区域。
最终标记和复制时会STW。
可通过JVM参数
-XX:MaxGCPauseMillis=200
指定停顿时间为200ms。
细节详解
Young Collection 跨代引用
在G1垃圾收集器中,老年代区域会划分为一个个更小的区域,称为Card。
每个 Region 都有一个 Remembered Set 与之对应。
在进行GC Root标记时,由于老年代存活对象多,比较耗时,所以会通过Remembered Set来记录老年代中引用了新生代区域的Card,称为dirty card。
上图中Card Table中粉色区域即为dirty card。
当新生代进行垃圾回收时,通过Remembered Set找到Eden区域对应的dirty card,直接从dirty card开始遍历GC Root,避免扫描整个老年代区域,这将会省下不少时间。
在新生代对象引用变更时通过 post-write barrier 标记dirty card。这个过程是异步的,会先将指令放到 dirty queue 中。会有一个线程去执行指令,更新 Remembered Set。