当前位置: 首页 > 知识库问答 >
问题:

当对象仍在作用域内时,java是否可以完成它?

穆鸿波
2023-03-14

我一直在研究我的代码中的一个bug,它似乎是由一些“丑陋的”终结器代码引起的。代码大致如下所示

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

我认为正在发生的事情是,Amain()的第二行之后被检测为没有引用,并由终结器线程获得GCD和完成--而for循环仍在发生,使用B,而A仍“在作用域内”。

这个可以用吗?允许java在对象超出范围之前对其进行GC吗?

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

共有1个答案

淳于博
2023-03-14

当对象仍在作用域内时,Java是否可以完成它?

是的。

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

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

注释掉println后,可以看到可达性规则是如何应用的。当代码到达循环时,线程无法访问A。因此,它是不可达的,因此必须进行终结和垃圾收集。

请注意,名称A仍然在作用域内,因为可以在封闭块内的任何地方使用A--在本例中是main方法体--从其声明到块的末尾。JLS§6.3中涵盖了确切的范围规则。但实际上,正如您所看到的,作用域与可达性或垃圾收集无关。

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

 类似资料:
  • 问题内容: 在下面的示例中,有两种功能上等效的方法: 但是在它们的first()中,字符串“ s1”显然可用于语句之前的垃圾回收。在second()字符串中,“ s1”仍然可以访问(尽管从代码审查的角度来看,它不再使用了)。 我的问题是-jvm规范中是否有任何内容说明一旦在堆栈中未使用变量,便可以将其用于垃圾回收了? 编辑: 有时变量可以像完全渲染的图像一样引用对象,并且对内存有影响。 我问是出于

  • 我制作了一个类 在另一个类中 正如您所看到的,我创建了这个数组,并将UImages与txt和txt2一起放置在其中。简单地说,我要向用户显示一个图像,然后输入一个描述图像的输入,然后检查它是否匹配txt和txt2。在运行模拟器时,我得到以下错误: ***由于未捕获异常“nSunKnownKeyException”而终止应用程序,原因:“[ SetValue:ForUndefinedKey:]:对于

  • 是否可以在操作中发布IFormCollection和Object? 我尝试从Angular向WebAPI发出post请求,请求是上传文件和模型的组合。 角度代码: 如何实现这个WebAPI? 更新:我正在考虑将所有内容添加到FormCollection中,但这对于解析数据来说是非常糟糕的代码

  • 问题内容: 我正在计划制作Java Swing应用程序,并且想知道是否仍在使用Swing或是否已将其替换为其他东西。 提前致谢! 问题答案: 我们仍然使用它。并非所有的东西都是Web应用程序,到目前为止,已经进行了一些尝试性的替换(例如,将Eclipse写入到 SWT 中)。SWT拥有一个本机层,将基础调用包装到本机窗口层。它仅适用于有限的平台集,并且当然需要一些第三方共享库。我敢说,SWT应用程

  • 问题内容: 可以说我在代码中的某个位置有一个按钮:“ JButton closeButton”。我不知道它叫“ closeButton”,但这是我想找出的。 在运行时,该按钮将被单击,一旦完成,我就可以通过反射和AWT api找到很多关于它的信息-但是我不能做的就是找出它的位置- 在代码中如何调用它,名字叫什么它声明为(“ closeButton”)。 是否可以从JVM中找到它? 有没有一种方法可

  • 问题内容: 我正在调试一些旧代码,在这些代码中,我们有一个似乎在外部更改的缓存对象。 如果我知道它的对象标识符(在调试时),是否有某种方法可以“监视”它,以便如果同一线程或另一个线程中的某些其他代码试图修改其状态,将触发我的调试? 我不能仅使用表达式监视它,因为在其他地方可能有对该对象的引用,并且同一类有很多实例。 问题答案: 当值更改时,在要停止的代码中设置一个断点。 从断点视图开始。 选择断点