WeakReferenced 对象在调用 System.gc() 后未被垃圾回收

WeakReferenced object is not garbage collected after calling System.gc()

我是 Java 的新手。我现在正在学习 WeakReference 的概念。我遇到了一个可能看起来很愚蠢的问题,但我只想找出原因。问题是:根据 Java 文档,"Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed."

所以我做了这个小测试:

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() 仍然可以 return 对象,我期望它为 null,并且没有调用方法 finalize()。那么出了什么问题呢?提前感谢您的帮助! :)

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

来自the documentation

Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

(强调我的)

将来,您可以使用 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!");
    }
}

首先,System.gc() 不能保证垃圾回收。相反,它只是一个提示 "It's a good time to run garbage collection".

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

因为我们手头有两个任务

  1. 确保垃圾收集
  2. 不要保留任何对您希望被垃圾回收的对象的强引用

让我们对您的代码做一点修改

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!");
    }
}