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
- 变量应该以小写字母开头),因为终结器通常运行在另一个线程中。
提问时间 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
- 变量应该以小写字母开头),因为终结器通常运行在另一个线程中。