从finalize的执行来看什么是GC Root

首先我们来了解一下finalize方法,finalize由对象上的垃圾回收器在垃圾收集确定没有更多对该对象的引用(GC root不可达)时调用。子类重写finalize方法来处置系统资源或执行其他清理工作。

finalize

added in API level 1
protected void finalize ()

Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the finalize method to dispose of system resources or to perform other cleanup.

了解一下它的某些性质,先不必知道为什么会这样:

  1. finalize方法由名为“Finalizer”的守护线程执行,只会被调用一次
  2. 在finalize方法中,可将待回收对象赋值给GC Root从而达到对象再生的目的

之后我们了解下GC Root,GC Root即Garbage collection root,Android开发者官网GC Root的阐述如下:

There are several kinds of garbage collection roots in Java:

  • references on the stack
  • Java Native Interface (JNI) native objects and memory
  • static variables and functions
  • threads and objects that can be referenced
  • classes loaded by the bootstrap loader
  • finalizers and unfinalized objects
  • busy monitor objects

在JAVA中有如下几种GC Root:

  1. 在栈上的引用
  2. JNI本地对象和内存
  3. 静态变量和函数
  4. 线程和可以被引用的对象
  5. 被bootstrap loader加载的类
  6. finalizers和unfinalized的对象
  7. 被占用的监视器对象

我们知道GC对垃圾对象的判断依据是对象是否从GC Root可达,结合finalize方法的API解释,可知对象不可达时会调用对象的finalize方法。接下来我们用代码来验证一下上述几种GC Root:

一、静态变量

public class RootTest {
    static int gcTime = 0;
    
    //静态变量
    static RootTest rootTest = null;

    public static void main(String[] args) throws InterruptedException {
        rootTest = new RootTest();
        gc();
        Thread.sleep(1000);

        gcTest();
        gcTest();
    }

    static void gcTest() throws InterruptedException {
        rootTest = null;
        gc();
        Thread.sleep(1000);
        if (rootTest == null)
            System.out.println("rootTest dead");
        else
            System.out.println("rootTest alive");
    }

    static void gc() {
        System.gc();
        System.out.println("gc " + ++gcTime);
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("RootTest finalize() " + Thread.currentThread().getName());
        rootTest = this;
    }
}

我们使用了静态变量rootTest引用RootTest对象后立即执行一次gc,然后执行两次gcTest:

  1. 将rootTest置为null
  2. 强制执行gc
  3. 休息1s等Finalizer线程执行finalize方法
  4. 判断rootTest状态

运行结果:

gc 1
gc 2
RootTest finalize() Finalizer
rootTest alive
gc 3
rootTest dead

可见,第一次执行gc后,GC发现RootTest对象是可达的,RootTest对象的finalze方法没有被调用。

第二次将rootTest置为null后,执行gc时GC发现RootTest对象不可达,RootTest对象的finalze方法被调用,finalze中RootTest对象再生。

第三次将rootTest置为null后,执行gc时GC发现RootTest对象不可达,RootTest对象的finalze方法被调用过了,这次不会再被调用,RootTest对象被回收。

二、线程、栈上的引用

public class RootTest {
    static int gcTime = 0;

    public static void main(String[] args) throws InterruptedException {

        //栈上的引用
        Thread thread1 = new Thread() {
            @Override
            public void run() {
                System.out.println("Thread1 run over");
            }

            @Override
            protected void finalize() throws Throwable {
                super.finalize();
                System.out.println("Thread1 finalize() " + Thread.currentThread().getName());
            }
        };
        thread1.start();

        new Thread() {
            @Override
            public void run() {
                System.out.println("Thread2 run over");
            }

            @Override
            protected void finalize() throws Throwable {
                super.finalize();
                System.out.println("Thread2 finalize() " + Thread.currentThread().getName());
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                int x = 0;
                while (x < 3) {
                    System.out.println("Thread3 run " + ++x);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Thread3 run over");
            }

            @Override
            protected void finalize() throws Throwable {
                super.finalize();
                System.out.println("Thread3 finalize() " + Thread.currentThread().getName());
            }
        }.start();

        gc();
        Thread.sleep(5000);
        gc();

        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                gc();
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    static void gc() {
        System.gc();
        System.out.println("gc " + ++gcTime);
    }
}

在main方法中起三个子线程,第一个执行打印后立即结束运行但是会被栈中的局部变量引用,第二个执行打印后立即结束运行,第三个会循环三次打印,接着执行三次gc

运行结果:

Thread1 run over
Thread2 run over
Thread3 run 1
gc 1
Thread2 finalize() Finalizer
Thread3 run 2
Thread3 run 3
Thread3 run over
gc 2
Thread3 finalize() Finalizer
gc 3
Thread1 finalize() Finalizer

首先子线程Thread1运行结束,Thread2运行结束,Thread3开始执行

然后,在Thread3运行期间第一次执行gc,可以看到Thread2的finalze方法被调用

然后,在Thread3运行结束后第二次执行gc,可以看到Thread3的finalze方法被调用

然后,当main方法运行结束后第三次执行gc,可以看到Thread1的finalze方法被调用

三、被占用的监视器对象

public class RootTest {
    static int gcTime = 0;

    public static void main(String[] args) throws InterruptedException {

        new UnusedLock();

        new Thread() {
            @Override
            public void run() {
                int x = 0;
                synchronized (new UsedLock()) {
                    while (x < 3) {
                        System.out.println("Thread run " + ++x);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("Thread run over");
                }
            }

            @Override
            protected void finalize() throws Throwable {
                super.finalize();
                System.out.println("Thread finalize() " + Thread.currentThread().getName());
            }
        }.start();

        gc();
        Thread.sleep(5000);
        gc();
        Thread.sleep(5000);
    }

    static void gc() {
        System.out.println("gc start " + ++gcTime);
        System.gc();
        System.out.println("gc over " + gcTime);
    }
}


class UsedLock {
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("UsedLock finalize()");
    }
}

class UnusedLock {
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("UnusedLock finalize()");
    }
}

直接new一个不会被占用的监视器对象,然后启动一个循环打印三次的子线程,并在其中使用一个被其占用的监视器对象,接着执行两次gc

运行结果:

gc start 1
Thread run 1
gc over 1
UnusedLock finalize()
Thread run 2
Thread run 3
Thread run over
gc start 2
gc over 2
UsedLock finalize()
Thread3 finalize() Finalizer

首先,在Thread3执行期间第一次执行gc,可以看到UnusedLock的finalze方法被调用

然后,当Thread3执行完成后第二次执行gc,可以看到UsedLock和Thread的finalize方法都被调用了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值