新生代垃圾回收的过程:
- 首先要找到根对象
- 然后对根对象进行可达性分析,找到存活对象
- 对存活对象进行复制,复制到幸存区
产生问题:
- 找到新生代对象的根对象,根对象有一部分是来自老年代的,而老年代存活的对象一般都特别多,如果去遍历整个老年代,效率非常低。
应对措施:
- 采用了cart table的方式,对老年代进行细分,分成了许多个card,每个card大约是512K。如果老年代某个对象,引用了新生代的对象,我们把这个老年代的对象标记为脏card。这样,找老年代的根对象时,就不用遍历整个老年代了,只需要关注脏card,减小搜索范围,提高效率。如下图,粉色为脏card,绿色为伊甸园区,蓝色为幸存者区,橙色为老年代。
-
老年代有脏卡标记,而新生代则有remembered Set记录外部对它的引用,记录都有哪些脏卡。将来对新生代进行垃圾回收时,先通过remembered Set 知道有哪些脏卡,然后通过脏卡区域遍历GC Root。
-
在引用变更时通过post-write barrier + dirty card queue,在每次的引用变更时,都要更新标记脏卡(异步操作,把更新的指令放到一个队列(dirty card queue)之中,将来由一个线程,执行更新操作)。