java可以在对象仍在范围内时完成它吗? [英] Can java finalize an object when it is still in scope?

查看:20
本文介绍了java可以在对象仍在范围内时完成它吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在调查我的代码中的一个错误,该错误似乎是由一些丑陋"的终结器代码引起的.代码大概是这样的

I've been looking into a bug in my code that seems to be caused by some "ugly" finalizer code. The code looks roughly like this

public class A {
   public B b = new B();
   @Override public void finalize() {
     b.close();
   }
}

public class B {
   public void close() { /* do clean up our resources. */ }
   public void doSomething() { /* do something that requires us not to be closed */ } 
}

void main() {
   A a = new A();
   B b = a.b;
   for(/*lots of time*/) {
     b.doSomething();
   }
}

我认为正在发生的事情是 a 被检测为在 main() 的第二行之后没有引用,并通过终结器进行 GC 并最终确定线程 - 当 for 循环仍在发生时,使用 ba 仍在范围内".

What I think is happening is that a is getting detected as having no references after the second line of main() and getting GC'd and finalized by the finalizer thread - while the for loop is still happening, using b while a is still "in scope".

这合理吗?java是否允许在对象超出范围之前对其进行GC?

Is this plausable? Is java allowed to GC an object before it goes out of scope?

注意:我知道在终结器中做任何事情都是不好的.这是我继承并打算修复的代码 - 问题是我是否正确理解了根本问题.如果这是不可能的,那么更微妙的东西一定是我的错误的根源.

Note: I know that doing anything inside finalizers is bad. This is code I've inherited and am intending to fix - the question is whether I'm understanding the root issue correctly. If this is impossible then something more subtle must be the root of my bug.

推荐答案

Java 能否在对象仍在作用域内时对其进行终结?

Can Java finalize an object when it is still in scope?

是的.

但是,我在这里很迂腐.Scope 是决定名称有效性的语言概念.一个对象是否可以被垃圾收集(并因此最终确定)取决于它是否可达.

However, I'm being pedantic here. Scope is a language concept that determines the validity of names. Whether an object can be garbage collected (and therefore finalized) depends on whether it is reachable.

来自 ajb 的答案 引用了 JLS 的重要段落,几乎得到了 (+1).但是我不认为它直接适用于这种情况.JLS §12.6.1 还说:

The answer from ajb almost had it (+1) by citing a significant passage from the JLS. However I don't think it's directly applicable to the situation. JLS §12.6.1 also says:

reachable 对象是可以从任何活动线程在任何潜在的持续计算中访问的任何对象.

A reachable object is any object that can be accessed in any potential continuing computation from any live thread.

现在考虑将其应用于以下代码:

Now consider this applied to the following code:

class A {
    @Override protected void finalize() {
        System.out.println(this + " was finalized!");
    }

    public static void main(String[] args) {
        A a = new A();
        System.out.println("Created " + a);
        for (int i = 0; i < 1_000_000_000; i++) {
            if (i % 1_000_000 == 0)
                System.gc();
        }
        // System.out.println(a + " was still alive.");
    }
}

在 JDK 8 GA 上,这将每次都完成 a.如果您取消注释最后的 printlna 将永远不会最终确定.

On JDK 8 GA, this will finalize a every single time. If you uncomment the println at the end, a will never be finalized.

通过注释掉println,可以看到可达性规则是如何应用的.当代码到达循环时,线程不可能访问a.因此它是不可访问的,因此需要进行终结和垃圾回收.

With the println commented out, one can see how the reachability rule applies. When the code reaches the loop, there is no possible way that the thread can have any access to a. Thus it is unreachable and is therefore subject to finalization and garbage collection.

请注意,名称 a 仍在 范围内,因为可以在封闭块内的任何位置使用 a —— 在这种情况下,main 方法体——从它的声明到块的结尾.JLS § 中涵盖了确切的范围规则6.3.但实际上,如您所见,范围与可达性或垃圾收集无关.

Note that the name a is still in scope because one can use a anywhere within the enclosing block -- in this case the main method body -- from its declaration to the end of the block. The exact scope rules are covered in JLS §6.3. But really, as you can see, scope has nothing to do with reachability or garbage collection.

为了防止对象被垃圾回收,您可以将对其的引用存储在静态字段中,或者如果您不想这样做,您可以稍后在相同的方法中使用它来保持它的可访问性耗时的循环.调用像 toString 这样的无害方法就足够了.

To prevent the object from being garbage collected, you can store a reference to it in a static field, or if you don't want to do that, you can keep it reachable by using it later on in the same method after the time-consuming loop. It should be sufficient to call an innocuous method like toString on it.

这篇关于java可以在对象仍在范围内时完成它吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆