调用System.gc()后,WeakReferenced对象不是垃圾回收

时间:2018-06-06 10:47:45

标签: java reference garbage-collection weak-references

我是Java的新学习者。我现在正在学习WeakReference的概念。我遇到了一个可能看起来很愚蠢的问题,但我只是想弄清楚原因。问题是:根据Java doc,"弱引用对象,它们不会阻止它们的引用被最终化,最终化,然后回收。"

所以我做了这个小测试:

import java.lang.ref.WeakReference; 

public class A {
    public static void main(String[] args) {
        A a = new A();
        WeakReference<A> wr = new WeakReference<>(a);
        a = null;

        A a1 = wr.get();

        System.out.println(a);
        System.out.println(a1);

        try {
            System.gc();

            Thread.sleep(10000);

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(a1);
    }

    @Override
    protected void finalize( ) {
        System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
    }
}

但是,我注意到在GC运行后,wr.get()仍然可以返回我期望为null的对象,并且未调用方法finalize()。出了什么问题?感谢您的帮助! :)

2 个答案:

答案 0 :(得分:3)

您的测试前提是有缺陷的。 System.gc()只是提示来运行垃圾收集器。它经常被忽略。

来自the documentation

  

调用gc方法建议表示Java虚拟机   努力回收未使用的物体,以便制造   他们目前占用的内存可用于快速重用。控制时   从方法调用返回,Java虚拟机做得最好   努力从所有废弃物体中回收空间。

(强调我的)

将来,您可以使用VM选项-verbose:gc-XX:+PrintGCDetails来查看垃圾收集器正在执行的操作。

更重要的是,您也非常快从弱引用中获取引用并将其重新引入强引用:

A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null; // no strong references remain
A a1 = wr.get(); // the instance now has a strong reference again

除非在这两个指令之间发生垃圾收集,否则该对象不会被垃圾收集。

如果你删除a1,你的代码就像我在运行它时所期望的那样(但是,由于我的答案的第一部分,你的里程可能会有所不同):

class A
{
    public static void main(String[] args)
    {
        A a = new A();
        WeakReference<A> wr = new WeakReference<>(a);
        a = null;

        System.out.println(a);

        try {
            System.gc(); // instance of A is garbage collected
            Thread.sleep(10000);

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(wr.get());
    }

    @Override
    protected void finalize( )
    {
        System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
    }
}

答案 1 :(得分:0)

首先,System.gc()无法确保垃圾回收。相反,它只是暗示“这是运行垃圾收集的好时机”。

其次,在调用A a1 = wr.get();之前放置System.gc()的代码中,它会创建对a引用的同一对象的新强引用,因此即使垃圾收集运行,对象不会被垃圾收集。

因为我们手头有两项任务

  1. 确保垃圾收集
  2. 不要对要收集垃圾的对象保留任何强引用
  3. 让我们对您的代码进行一些修改

    public class A {
        public static void main(String[] args) {
            A a = new A();
            WeakReference<A> wr = new WeakReference<>(a);
            a = null;
            // A a1 = wr.get(); Removing this, this does our 2nd task
            System.out.println(a);
            // System.out.println(a1); Removing this as a1 does not exists anymore
            try {
                while (null != wr.get()) { // 1st task done, the loop ensures sending the hint until your object collected
                    System.gc();
                    // Thread.sleep(10000); it does not have impact
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(wr.get()); // Obviously prints null
        }
    
        @Override
        protected void finalize() {
            System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
        }
    }