我正在读书Java 平台性能 http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html(遗憾的是,自从我最初提出这个问题以来,该链接似乎已经从互联网上消失了)并且 A.3.3 节让我担心。
我一直在假设超出范围的变量将不再被视为 GC 根,但本文似乎与此相矛盾。
最近的 JVM,特别是 Sun 的 1.6.0_07 版本,仍然有这个限制吗?如果是这样,那么我有很多代码需要分析......
我问这个问题是因为这篇论文是 1999 年的——有时事情会发生变化,特别是在 GC 领域。
由于该论文不再可用,我想解释一下我的担忧。该论文暗示,方法内部定义的变量将被视为 GC 根,直到方法退出,而不是代码块结束。因此,必须将变量设置为 null 才能允许垃圾收集引用的对象。
这意味着 main() 方法(或包含无限循环的类似方法)的条件块中定义的局部变量将导致一次性内存泄漏,除非您在变量退出范围之前将其清空。
代码来自选择的答案 https://stackoverflow.com/a/271824/7938很好地说明了这个问题。在文档中引用的 JVM 版本上,当 foo 对象在 try 块末尾超出范围时,无法对其进行垃圾回收。相反,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)上打印:
从 main 构建
从 main 完成
所以看起来问题已经解决了。
请注意,使用 System.gc() 而不是循环不会导致对象因某种原因被收集。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)