java终结器和gc

时间:2015-12-28 19:50:33

标签: java garbage-collection finalizer

有时间质疑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。 (System.GC和终结器强制至少为'1'。)

相反,它始终为0.

任何人都可以解释这种行为吗?

(另外,静态成员字段是否与类实例无关,并且在代码执行期间永远不会被销毁?)

1 个答案:

答案 0 :(得分:2)

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

你运行这行10次:

SomeSubscriber subscriber = new SomeSubscriber(publisher);

这会调用SomeSubscriber的构造函数,其中包含:

publisher.subscribe(this);

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

actions.add(subscriber.getAction());

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

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

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

    return new Action();
}

它会创建本地类的实例。该实例包含封闭的SomeSubscriber对象的实例。实际上,它有两个这样的实例 - me,以及每个内部类具有的封闭实例的隐式引用。本地课程是内部课程!

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

确保您还指定publisher = null,然后可能您将能够看到正在运行的结束。我还建议将Count声明为volatile(而不是将其称为Count,但count - 变量应以小写字母开头),因为通常会将终结器设为以不同的方式运行。