一般情况任务虚拟机GC回收内存中的不可达对象,但是这是不完全对的,因为在内存中的对象有一部分不可达的对象也是不可以被回收的,这些对象就是 可复活对象。

引入一个概念就是可触及。

可触及的对象,为从root也就是根节点可以触及到这个对象。这个对象就是可触及对象。一般的理解GC就是销毁不可触及的对象。

而还有一类对象是不可触及的但是不能被GC回收 ,这些对象就是可复活对象。那么什么是可复活对象呢?

一旦所有引用被释放这个对象就会变成可复活状态,那么这个对象就是可复活对象。why?

由下面这张图可以看到在java中的所有类的超类object 有一个finalize方法。

JAVA 丢掉最近不使用的集合_gc


就是这个方法可以把被释放的对象重新复活。如果一个对象被释放之后 可能被复活那么这个对象就不能被GC干掉。

那么岂不是所有的对象都不能被干掉了?肯定不是的,不然jvm内存早就爆炸了,就是在finalize执行之前这个对象是可复活对象,但是finalize一旦执行之后 这个对象就变成了不可复活对象,只能等着GC干掉。

在这里做一点总结:

GC干掉的不是不可达 或者说是不可触及的对象,而是干掉不可复活的不可触及的对象。

下面做一个代码demo:

package realive;

public class CanReliveObj {
    public static CanReliveObj obj;
    @Override
    protected  void finalize() throws Throwable {
        super.finalize();
        System.out.println("canrelive obj finalize obj");
        obj = this;
    }
    @Override
    public String toString(){
        return "i am canreliveobj";
    }
    public static void main(String[] args) throws InterruptedException {
        obj = new CanReliveObj();
        obj=null; 
        System.out.println("第一次gc");
        System.gc();
        Thread.sleep(1000);
        if(obj == null){
            System.out.println("obj 是 null");
        }else {
            System.out.println("obj 可用");
        }
        System.out.println("第二次gc");
        obj=null;
        System.gc();
        Thread.sleep(1000);
        if(obj==null){
            System.out.println("obj 是 null");
        }else {
            System.out.println("obj well");
        }
    }

}

执行结果:

第一次gc
canrelive obj finalize obj
obj 可用
第二次gc
obj 是 null

由上面的结果可以看出GC在finalize之后就不能再复活了。因为(打印了canrelive obj finalize obj 证明finalize被执行,引用被释放,状态变为不可复活状态)对象在第二次gc的时候被干掉了。

我们再这里只是对finalize进行试验,其实在obj被复活之后,如果不进行obj=null操作obj可能永远不会被回收 。

下面简单介绍一下finalize
1、避免使用finalize(),操作不慎会导致错误
2、优先级低,合适被调用不确定(何时GC也不确定)
3、可以使用try-catch-finally来代替