当java仍然在范围内时,java能够完成一个对象吗? [英] Can java finalize an object when it is still in scope?

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

问题描述

我一直在研究我的代码中的一个错误,它似乎是由一些丑陋的终结器代码造成的。代码看起来就像这样

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



public class B {
public void close(){/ *清理我们的资源。 * /}
public void doSomething(){/ *做一些需要我们不关闭的东西* /}
}

void main(){
A a = new A();
B b = a.b; $ / $ b $(/ *很多时间* /){
b.doSomething();


$ / code $ / pre

我认为正在发生的是<$ c $在
第二行 main()之后,c> a
被检测为没有引用,并且获取GC'd并最终完成使用 b ,而 a 循环仍然发生 c $ c>仍然在范围内。



这是否合理? java是否允许在对象超出作用域之前GC对象?



注意:我知道在终结器内部做任何事情都是不好的。这是我已经继承并打算修复的代码 - 问题是我是否正确理解根本问题。如果这是不可能的,那么更微妙的东西必须是我的bug的根源。

解决方案


定义一个对象,当它仍然在范围内?

是。



不过,我在这里很迂腐。 范围是确定名称有效性的语言概念。一个对象是否可以被垃圾回收(并因此最终确定)取决于它是否可以访问。

从ajb 收到的数据几乎都是通过引用JLS中的重要段落(+1)。但我认为这不适用于这种情况。 JLS §12.6.1还说:


可达对象是可以在任何潜在的持续计算中访问的任何对象来自任何活动线程。


现在考虑它适用于以下代码:

  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 +还活着。);


$ / code>

在JDK 8 GA上,这会完成 a 每一次。如果您在最后取消注释 println ,那么 a 永远不会最终确定。



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



请注意,名称 a 仍然<因为可以在封闭块中的任何地方使用 a - 在这种情况下, main >方法体 - 从其声明到块的结尾。准确的范围规则在JLS中涵盖 §6.3。但实际上,正如你所看到的,范围与可访问性或垃圾收集无关。



为了防止垃圾收集对象,可以存储对它的引用在一个静态字段中,或者如果不想这样做,可以通过在耗时循环之后的相同方法中稍后使用它来保持它可达性。调用一个无害的方法就足够了,比如 toString 就可以了。


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();
   }
}

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 the finalizer thread - while the for loop is still happening, using b while a is still "in scope".

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.

解决方案

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

Yes.

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.

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:

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.");
    }
}

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

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.

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.

To prevent the object from being garbage collected, you can store a reference to it in a static field, or if 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仍然在范围内时,java能够完成一个对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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