问题
我们通常说jvm识别垃圾对象有两个方法:
- 引用计数法
- 可达性分析
老年代肯定是用的可达性分析,先标记GC roots,然后依据这些根对象来做遍历访问,能够访问的对象就是活的对象,其他对象就是没有引用的对象,可以回收,那么针对年轻代的垃圾回收,它是如何来标记的?
可达性分析
首先,引用计数法无法解决循环引用的问题,几乎不被采纳,可达性分析是一个比较好的方法,所以答案是YGC采用的也是可达性分析方法来做垃圾回收处理。那么YGC和FGC是都是可达性分析,也都要找GC Roots,那么2者找到的root集合都是一样的吗?如果是一样的,那么YGC也会把老年代的对象做可达性分析,这样遍历浪费的时间就太多了,毕竟年轻代的数据较小,并没有很多数据。所以垃圾回收算法是如何处理的呢?
card table
首先要了解一个概念:跨代引用,这是指老年代对象里有引用指向年轻代对象,所以年轻代没有GC Roots来做引用,可能也不能回收,因为老年代可能有,所以,为了知道对象 是否可以被回收,还需要遍历一遍老年代。那这就违背了分代回收节省时间的初衷了。那怎么办?
这就是card table里记录的东西了。不再需要通过搜索遍历old gen来获取他里面对象对young gen里对象的引用,查card table就OK了。而且YGC的时候,不会遍历老年代的对象,那么怎么识别是不是老年代呢?通常young gen与old gen都是有地址范围的,拿着指针对那地址范围查一下就好了。HotSpot VM老的GC都是要求整个GC堆在连续的地址空间上,只有一个分界线,一侧是young gen另一侧是old gen,所以检查分代的开销非常低;G1则需要遍历一个young gen region列表来获得young gen的地址范围。
总结一下:Young GC是不会找出old gen中的“无用对象”的。它连old gen的活的对象也不会关心。它只关心old gen里有没有引用指向young gen——这些引用必须作为root set的一部分,但它通常不关心这些引用是来自old gen里活的对象还是死的对象——old gen对象的死活要等做old gen GC或者full GC时才可以知道。HotSpot VM里只有CMS有old gen GC
备注:这里old gen 和 young gen 是指根对象,也是指GC roots。
HotSpot 使用 CardTable 记录老年代对年轻代的引用。把老年代按照 4KB 的大小分块,每一块对应在 CardTable 中都是1 bit。当值为1时,表示这4KB 的内存中有对年轻代的引用,需要加入到 GC Roots 中。
分代的好处
分代的好处 :
- 1)减少stop the world的时间;
- 2)提高内存分配的效率。第一点好理解,第二点不太清楚,是跟在新生代采用的复制算法有关吗,重新分配的时候直接修改指针地址即可。
参考博客
java的gc为什么要分代?
Java中的GCRoots到底有哪些?年轻代gc和老年代gc的GCRoots是如何区分的?