java 终结器和 gc

java finalizer and gc

提问时间 JAVA System.GC() 和 System.runFinilizer

public interface SomeAction {
    public void doAction();
}

public class SomePublisher {
    private List<SomeAction> actions = new ArrayList<SomeAction>();

    public void subscribe(SomeSubscriber subscriber) {
        actions.add(subscriber.getAction());
    }
}

public class SomeSubscriber {
    public static int Count;

    public SomeSubscriber(SomePublisher publisher) {
        publisher.subscribe(this);
    }

    public SomeAction getAction() {
        final SomeSubscriber me = this;
        class Action implements SomeAction {

            @Override
            public void doAction() {
               me.doSomething();
            }
        }

        return new Action();
    }

    @Override
    protected void finalize() throws Throwable {
        SomeSubscriber.Count++;
    }

    private void doSomething() {
        // TODO: something
    }
}

现在我试图在主块中强制执行 GC 和终结器。

 SomePublisher publisher = new SomePublisher();

        for (int i = 0; i < 10; i++) {
            SomeSubscriber subscriber = new SomeSubscriber(publisher);
            subscriber = null;
        }

        System.gc();
        System.runFinalization();

        System.out. println("The answer is: " + SomeSubscriber.Count);

因为 JAVA 不能保证调用 GC 调用(如 javadoc 和 JAVA 中所解释的那样 GC 调用不能保证被调用(如 javadoc 和 When is the finalize() method called in Java? 中所解释,

我的初始想法是它会随机输出 SomeSubscriber.Count。 (至少 '1' 作为 System.GC 和终结器的强制。)

相反,它始终为 0。

谁能解释一下这种行为?

(另外,静态成员字段是否独立于 class 个实例存在并且在代码执行期间永远不会被销毁?)

你的测试有一个缺陷 - 即使假设调用 System.gc()System.runFinalization() 实际上会 运行 GC 和终结,你创建的实例 不是 垃圾收集候选者,因此不会被最终确定或收集。

你运行这行10次:

SomeSubscriber subscriber = new SomeSubscriber(publisher);

这会调用 SomeSubscriber 的构造函数,它表示:

publisher.subscribe(this);

因此,发布者对象被赋予了对当前正在构造的对象的引用。它有什么作用?

actions.add(subscriber.getAction());

OK,所以它在订阅者上调用 getAction() 方法,并存储结果。 getAction() 是做什么的?

public SomeAction getAction() {
    final SomeSubscriber me = this;
    class Action implements SomeAction {

        @Override
        public void doAction() {
           me.doSomething();
        }
    }

    return new Action();
}

它创建了一个 local class 的实例。该实例包含封闭 SomeSubscriber 对象的实例。事实上,它有两个这样的实例——me,以及每个内部 class 都有的对封闭实例的隐式引用。本地 classes 是内部 classes!

因此,当您在 publisher 实例中存储您的操作列表时,您还会在其中存储对所有订阅者的引用。当你 运行 System.gc()System.runFinalization() 时,publisher 实例仍然存在,因此那些引用仍然存在,所以 none您的 SomeSubscriber 个实例实际上符合垃圾回收条件。

确保您也分配 publisher = null,然后 也许 您将能够看到最终确定 运行ning。我还建议将 Count 声明为 volatile(而不是将其称为 Count 而是 count - 变量应该以小写字母开头),因为终结器通常运行在另一个线程中。