从垃圾识别到收集器:详细聊聊Java的GC

个人博客

从垃圾识别到收集器:详细聊聊Java的GC | iwts’s blog

前言

聊GC,自然离不开JVM内存模型,建议先了解JVM内存模型相关内容,或者最起码了解堆相关的内容,GC主要处理的就是堆。

这里会从垃圾识别算法->GC算法->JVM 垃圾收集器,从发展演进的过程详细聊聊,内容会比较长。

垃圾识别算法

引用计数法

简单地说,就是对象被引用一次,在它的对象头上加一次引用次数,如果没有被引用(引用次数为 0),则认为此对象可回收。

看起来比较简单,只要没有变量引用这个具体的对象,那么就认为这个对象是没有用的,可以被GC回收掉。

但是这样可能会造成一个问题:循环引用。

循环引用问题

给个代码:

public class TestRC {
   

    TestRC instance;
    
    public TestRC(String name) {
   
    }

    public static  void main(String[] args) {
   
        // 第一步
        TestRC a = new TestRC("a");
        TestRC b = new TestRC("b");

        // 第二步
        a.instance = b;
        b.instance = a;

        // 第三步
        a = null;
        b = null;
    }
}

那么变量的引用过程:

最后导致了这样的情况,A和B互相引用,但是本质上这两个对象都应该是垃圾,因为完全没有被正经使用了。

采用引用计数法时,这个问题无解,所以目前GC算法都不会使用这个算法。

可达性算法

目前JVM一般都是采用这个方法来判断对象是否存活。

可达性算法的原理是以一系列叫做 GC Root 的对象为起点出发,引出它们指向的下一个节点,再以下个节点为起点,引出此节点指向的下一个结点。

这样通过 GC Root 串成的一条线就叫引用链,直到所有的结点都遍历完毕。

如果相关对象不在任意一个以 GC Root 为起点的引用链中,则这些对象会被判断为垃圾,会被 GC 回收。

文字可能略有难懂,看图:

等于说JVM本身维护了一个GC Roots的集合,每个GC Roots都有一条具体的引用链,只有在引用链上的对象才不会被回收。

那么对于循环引用的问题,虽然两个变量在循环引用,但是由于已经不在GC Roots的引用链上,所以依旧会被回收掉。

finalize 方法

算是一次误杀补偿的机会。当一次GC扫描中,发现一个对象没有在引用链上,那么就会先对这个对象执行一次finalize方法,看是否有GC Roots能和对象进行关联。如果有的话,就不对该对象执行GC。

但是finalize对于每个对象是只能执行一次的。如果该对象执行方法后没有被回收,那么第二次GC的时候又发现了这个对象,那么这次就不给机会了,直接回收掉。

GC Roots的选择

综上,GC Roots的选择就非常重要了。而GC Roots本身其实也是一个对象,但是这个对象的引用方,即变量,要级别够高,最好是方法/应用从最开始就出现的对象。所以GC Roots的选择有以下几种:

虚拟机栈中引用的对象

即栈帧中的本地变量表中的变量。会随着弹栈自己消失,消失前基本保证整个方法都在用。

public class Test {
   
    public void test() {
   
        Test a = new Test(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值