Skip to content
Go back

为什么重写object的finalize方法后,使用PhantomReference似乎未监听到对象的回收?

Published:  at  11:57 AM

未重写Object的finalize方法

    public static class MyObject {
    }

使用 PhantomReference 来监听引用是否被回收

        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        MyObject object = new MyObject();
        PhantomReference<MyObject> phantomReference = new PhantomReference<>(object, queue);
        object = null;
        System.gc();  // gc round 1, referenced by finalizer class
        Thread.sleep(1000);
        Reference<?> polled = queue.poll();  // detected reclaimed reference
        System.out.println(polled);

查看可以获取到 被回收的 PhantomReference

重写Object的finalize方法后

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

再次用上述代码测试:

会发现没有检测到引用被回收的信息。这是由于: 重写了 finalize 方法的对象在被gc线程检测到的时候,需要交由finalizer thread执行自定义的 finalize 方法,所以无法直接被标记回收,只能等待下一轮gc

所以大量使用 finalize 方法可能导致较大的gc压力

这里调用 System.gc() 建议jvm再增加一轮gc检测下是否会被回收

        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        MyObject object = new MyObject();
        PhantomReference<MyObject> phantomReference = new PhantomReference<>(object, queue);
        object = null;
        System.gc();  // gc round 1, referenced by finalizer class
        Thread.sleep(1000);
        System.gc();  // gc round 2, marked as unreachable reference
        Thread.sleep(1000);
        Reference<?> polled = queue.poll();  // detected reclaimed reference
        System.out.println(polled);

这里发现很大可能是可以检测到回收的:

引用

[1] https://www.zhihu.com/question/49760047


Suggest Changes

Previous Post
ThreadPoolExecutor的重要特性和概念
Next Post
nextjs的服务端渲染(SSR)