RSets
在实现部分垃圾收集(partial GC)时,如分代(CMS+ParNew)、分区(G1),为了部分收集时不需要全堆扫描也可以确定目标搜集区域的存活对象,引入Remembered Sets记录从非收集部分到收集部分的指针集合(Points-In):
- 分代收集:堆内存分为新生代和老年代,新生代可以单独回收,RSets记录从老年代到新生代的指针
- 分区收集:堆内存分成多个区域,CollectionSets决定哪些区域需要被回收,RSets记录从其他区域到CSets区域中的指针
GC为保证低停顿时间,实现了并行回收,GC线程与应用线程并行,导致浮动垃圾的问题,所以部分垃圾收集可以保证所有死的对象都是死的,但不能保证所有活的对象都是活的,这会导致内存浪费,是在时间和空间上的一种取舍。
G1回收流程
初始标记:包括STW,遍历根集合,将根集合直接引用的对象放入扫描栈(tracing stack)
并发标记:无STW,不断从扫描栈中取出对象,遍历整个堆中对象图,标记扫描到的对象并放入扫描栈,直至扫描栈为空,同时处理STAB logging write barrier中的对象引用
最终标记:有STW,继续处理STAB write barrier中剩余的对象引用,同时处理软引用(reference processing)
清理:有STW,清点和重置扫描状态,发现没有存活对象的区域直接回收
evacuation:全程STW,确定CSets(决定了哪些区域将被回收),将存活对象拷贝到新的区域,回收原区域
对G1,有两个收集模式,youngGC和mixGC
youngGC:回收全部eden和survivor区域,通过控制下次eden和survivor的区域数来控制youngGC的停顿时间
mixGC:回收全部eden和survivor区域,以及部分O区
注意两个模式新生代都会被回收
G1没有fullGC概念,需要fullGC时,调用serialOldGC进行全堆扫描(包括eden、survivor、o、perm)
一个假想的混合的STW时间线
- 启动程序
- -> young GC
- -> young GC
- -> young GC
- -> young GC + initial marking
- (... concurrent marking ...)
- -> young GC (... concurrent marking ...)
- (... concurrent marking ...)
- -> young GC (... concurrent marking ...)
- -> final marking
- -> cleanup
- -> mixed GC
- -> mixed GC
- -> mixed GC
- ...
- -> mixed GC
- -> young GC + initial marking
- (... concurrent marking ...)
初始标记借用YGC的STW阶段完成
YGC可以发生在并发标记阶段
最终标记阶段不能发生YGC,必须等待YGC结束才可以开始