深入理解JVM底层原理实现
深入理解JVM底层
三色标记原理
垃圾回收只要从GC Roots 出发,只要被扫描过1次以后,会将该对象标记为黑色,接着扫该对象被引用的对象,当刚开始扫该对象的时候,会将对象变为灰色,没有还没有扫到的对象为灰色,当gc全部执行完以后,白色的对象为垃圾对象,可以进行回收
三色标记在并发场景下会有哪些问题呢
当从一个GC ROOTS下开始扫描,我们举2个线程同时进行可达性分析,线程1扫描完成以后,发现没有垃圾回收,认为自己扫的cardTable块没有可以回收的对象,所有的对象都在被引用,但是线程2还在进行垃圾回收,此时线程1中的某个对象指向了线程2的某个对象,并且将线程2中的对象引用置为空,此时线程2不会扫描的该对象,并且线程1由于已经扫描完成,认为,所有的对象都可达。不可回收。此时该对象其实不为垃圾对象,但是也没有标记成黑色,垃圾回收的时候,会将该对象一起回收。
垃圾收集器是如何解决三色标记的呢
cms垃圾收集器
Incremental Update 算法(增量更新算法)
当一个白色对象被一个黑色对象引用,将黑色对象重新标记为灰色,让垃圾回收器重新扫描
因为变成灰色的成员还要重新扫,重新再来一遍,效率太低了。
G1垃圾收集器
SATB( snapshot at the begining) 顾名思义在收集开始的时候做一次快照,
当 B 和 C 消失的时候要把这个引用推到 GC 的堆栈,保证 C 还能被 GC 扫描到,最重要的是要把这个引用推到 GC 的堆栈,是灰色对象指向白色的引用,如果一旦某一个引用消失掉了,我会把它放到栈(GC 方法运行时数据也是来自栈中),我其实还是能找到它的,我下回直接扫描他就行了,那样白色就不会漏标
跨代引用
老年代的对象引用新生代的对象,如果进行一次minorGC,只回收新生代的垃圾,此时会不会将老年代引用的对象当做垃圾回收掉呢?答案是不会。
jvm在新生代垃圾回收的时候,会将老年代的引用视为GCROOT,那么会每次的去扫描整个老年代吗?这样性能会有好大的影响。其实,jvm在垃圾回收过程中会根据地址端做一个cardTable,通过位图法的方式,将每个地址有引用记录为1,没有引用则记录为0 ,这样每次只去扫描一次存在0的cardTable所对应的地址空间即可。
Rset记忆集
在G1中每一个Region都会存在1个记忆集,而CMS中记忆集只存在于年轻代,记忆集是只用来记录对象引用关系的集合