java - 在最近的 JVM 中,不可见的引用仍然是一个问题吗?

标签 java memory-leaks garbage-collection jvm sun

我正在阅读 Java Platform Performance (遗憾的是,自从我最初提出这个问题以来,该链接似乎已经从互联网上消失了),A.3.3 节让我担心。

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

最近的 JVM,尤其是 Sun 的 1.6.0_07 版本,是否还有这个限制?如果是这样,那我还有很多代码要分析……

我问这个问题是因为这篇论文是 1999 年的 - 有时情况会发生变化,尤其是在 GC 领域。


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

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

来自 chosen answer 的代码很好地说明了这个问题。在文档中引用的 JVM 版本上,当 foo 对象在 try block 结束时超出范围时,无法进行垃圾回收。相反,JVM 将保持打开引用直到 main() 方法结束,即使任何东西都不可能使用该引用。

这似乎是一个想法的起源,即使变量引用为空将有助于垃圾收集器,即使该变量即将退出范围。

最佳答案

这段代码应该可以清除它:

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];
    } 
  }
}

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

Constructing from main

Finalizing from main

看来问题已经解决了。

请注意,使用 System.gc() 代替循环不会因为某种原因导致对象被收集。

关于java - 在最近的 JVM 中,不可见的引用仍然是一个问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/271613/

相关文章:

ios - 内存不规则增加只发生在 iPhone XS Max 上

java - 结果集异常 - 在结果集开始之前

java - 使用常量字符串作为 Enum 构造函数参数

c - strdup 和内存泄漏

python - 多次将 numpy.argpartition() 分配给列表元素时出现内存泄漏

java - 我应该如何针对我的应用程序调整 CMS?

.net - 拳击会在 .NET 中产生垃圾吗?

javascript - 当您引用 DOM 对象 (var a=document...) 并且通过 Parent.innerHTML ='' 删除该 DOM 对象时会发生什么?

java - 测试人员登录和 Spring Security

java - 使用 ArangoDB 和 Java 实现最短路径