隐形引用在最近的JVM中仍然是个问题吗?

Bil*_*ell 23 java garbage-collection jvm memory-leaks sun

我正在阅读Java平台性能(遗憾的是,因为我最初提出这个问题,链接似乎从互联网上消失了),A.3.3节让我很担心.

我一直在假设退出范围的变量不再被视为GC根,但本文似乎与此相矛盾.

最近的JVM,特别是Sun的1.6.0_07版本,仍然有这个限制吗?如果是这样,那么我有很多代码要分析......

我问这个问题是因为这篇论文是从1999年开始的 - 有时情况发生了变化,特别是在GC世界.


由于论文不再可用,我想解释一下这个问题.本文暗示,在方法退出之前,在方法内定义的变量将被视为GC根,而不是直到代码块结束.因此,必须将变量设置为null,以允许引用的Object被垃圾回收.

这意味着在main()方法中的条件块中定义的局部变量(或包含无限循环的类似方法)将导致一次性内存泄漏,除非在它退出范围之前将变量置为空.

所选答案的代码很好地说明了这个问题.在文档中引用的JVM版本中,当foo对象在try块结束时退出作用域时,不能对其进行垃圾回收.相反,JVM将保持打开引用直到main()方法结束,即使任何东西都不可能使用该引用.

这似乎是一个想法的起源,即使变量即将退出范围,将变量引用置零将有助于垃圾收集器输出.

Ras*_*ber 6

这段代码应该清除它:

public class TestInvisibleObject{
  public static class PrintWhenFinalized{
    private String s;
    public PrintWhenFinalized(String s){
      System.out.println("Constructing from "+s);
      this.s = s;
    }
    protected void finalize() throws Throwable {
      System.out.println("Finalizing from "+s);
    }   
  }
  public static void main(String[] args) {
    try {
        PrintWhenFinalized foo = new PrintWhenFinalized("main");
    } catch (Exception e) {
        // whatever
    }
    while (true) {
      // Provoke garbage-collection by allocating lots of memory
      byte[] o = new byte[1024];
    } 
  }
}
Run Code Online (Sandbox Code Playgroud)

在我的机器(jdk1.6.0_05)上打印:

从主要建构

从主要结束

所以看起来问题已得到解决.

请注意,使用System.gc()而不是循环不会导致由于某种原因收集对象.

  • 在回答关于System.gc()的最终声明时:调用System.gc()并不能保证立即收集 - 这只是一个请求.它可能完全被忽略了. (2认同)