java终结器和gc
是时候质疑JAVA System.GC()和System.runFinilizer了java终结器和gc,java,garbage-collection,finalizer,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(SomeSubscr
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
}
}
公共接口操作{
公共无效行为();
}
公共类发布者{
私有列表操作=新建ArrayList();
公共无效订阅(SomeSubscriber){
actions.add(subscriber.getAction());
}
}
公共类订阅服务器{
公共静态整数计数;
公共SomeSubscriber(SomePublisher发布者){
publisher.subscribe(这个);
}
public SomeAction getAction(){
最终结果:me=此;
类动作实现了一些动作{
@凌驾
公共无效行为(){
我做某事;
}
}
返回新操作();
}
@凌驾
受保护的void finalize()抛出可丢弃的{
SomeSubscriber.Count++;
}
私人无效剂量(){
//托多:什么
}
}
现在我试图在主块中强制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);
SomePublisher=newsomepublisher();
对于(int i=0;i<10;i++){
SomeSubscriber=新的SomeSubscriber(发布者);
订户=null;
}
gc();
System.runFinalization();
系统退出。println(“答案是:“+SomeSubscriber.Count”);
由于JAVA GC调用不保证被调用(如javadoc中所述),并且由于JAVA GC调用不保证被调用(如javadoc和
我最初的想法是,它会输出随机的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()
方法,并存储结果
public SomeAction getAction() {
final SomeSubscriber me = this;
class Action implements SomeAction {
@Override
public void doAction() {
me.doSomething();
}
}
return new Action();
}
它创建一个本地类的实例。该实例包含一个封闭的SomeSubscriber
对象的实例。事实上,它有两个这样的实例-me
,以及每个内部类对封闭实例的隐式引用。本地类是内部类
因此,当您在publisher
实例中存储操作列表时,也会在其中存储对所有订阅者的引用,publisher
实例仍处于活动状态,因此这些引用仍处于活动状态,因此您的SomeSubscriber
实例实际上没有一个符合垃圾收集条件。
请确保您还分配了
publisher=null
,然后您可能会看到正在运行的定稿。我还建议将Count
声明为volatile
(并且不要将其称为Count
,而是Count
——变量应该以小写字母开头),因为终结器通常在不同的线程中运行。如果您不知道什么是静态字段,那么不应该担心终结器或gc。静态字段是存在的类变量,没有实例化类实例共享的类。“不保证调用”的哪一部分你不明白吗?你不应该显式调用System.gc()
。在最好的情况下,它不会做任何事情,在最坏的情况下,它总是会导致世界gc完全停止(例如,当CMS收集器正在使用时)。如果你看到techloris_109示例,System.gc()手动调用,并在实例为空后运行finalize块。为什么在我的情况下不会发生相同的情况?就是这样!所以问题不在于GC,而在于本地类引用!即使您解决了引用问题,finalize()也无法保证方法执行。请看:@ravindra这是真的,但是,这些测试通常会取得一些成功,并且是一个重要的学习工具。不过,正确地执行它们很重要。