编程语言
首页 > 编程语言> > java终结器和gc

java终结器和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.
(System.GC和终结器强制至少为’1′.)

相反,它始终为0.

谁能解释这种行为?

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

解决方法:

你的测试有一个缺陷 – 即使假设调用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对象的实例.实际上,它有两个这样的实例 – 我,以及每个内部类具有的封闭实例的隐式引用.本地课程是内部课程!

因此,当您在发布者实例中存储操作列表时,还会存储对其中所有订阅者的引用.当您运行System.gc()和System.runFinalization()时,发布者实例仍处于活动状态,因此这些引用仍然存在,因此您的SomeSubscriber实例中没有一个实际符合垃圾回收的条件.

确保你还分配publisher = null,然后你可能会看到正在运行的终结.我还建议将Count声明为volatile(并且不要将其称为Count但计数 – 变量应该以小写字母开头),因为终结器通常在不同的线程中运行.

标签:java,garbage-collection,finalizer
来源: https://codeday.me/bug/20190702/1356396.html