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