希望是一个简单的问题。以循环链接列表为例:
class ListContainer
{
private listContainer next;
<..>
public void setNext(listContainer next)
{
this.next = next;
}
}
class List
{
private listContainer entry;
<..>
}
现在因为它是一个循环链接列表,当添加一个元素时,它在它的下一个变量中有一个对它自己的引用。删除列表中唯一的元素时,条目设置为null。是否需要将ListContainer.next设置为null以及垃圾收集器释放它的内存还是自动处理这样的自引用?
答案 0 :(得分:23)
仅依赖于引用计数的垃圾收集器通常容易受到诸如此类收集自引用结构的影响。这些GC依赖于对对象的引用数量的计数,以便计算给定对象是否可达。
非引用计数方法应用更全面的可达性测试来确定对象是否有资格被收集。这些系统定义了一个总是被认为是可达的对象(或一组对象)。任何可从此对象图中获得引用的对象都被视为不适合收集。不能直接从此对象访问的任何对象。因此,周期不会影响可达性,并且可以收集。
另见tracing garbage collectors上的维基百科页面。
答案 1 :(得分:14)
如果您依赖于对引用进行计数以确定对象是否已死,则循环引用是一个(可解决的)问题。没有java实现使用引用计数,AFAIK。较新的Sun JRE使用多种类型的GC混合,我认为所有标记和扫描或复制。
答案 2 :(得分:7)
对此的实际答案取决于实现。 Sun JVM跟踪一些根对象(线程等),当它需要进行垃圾收集时,跟踪哪些对象可以从那些对象访问并保存它们,丢弃其余对象。它实际上比允许一些优化更复杂,但这是基本原则。这个版本并不关心循环引用:只要没有活动对象持有对死亡对象的引用,它就可以被GCed。
其他JVM可以使用称为引用计数的方法。当为对象创建引用时,某些计数器会递增,当引用超出作用域时,计数器会递减。如果计数器达到零,则完成对象并收集垃圾。但是,这个版本确实允许循环引用永远不会被垃圾收集的可能性。作为一种安全措施,许多此类JVM都包含一种备份方法,用于确定哪些对象实际上已死亡,并定期运行以解析自引用并对堆进行碎片整理。
答案 3 :(得分:5)
作为一个不回答的问题(现有答案已经足够),如果您对GC感兴趣,可能需要查看JVM垃圾收集系统上的白皮书。 (任何,只是谷歌JVM垃圾收集)
我对所使用的一些技术感到惊讶,当阅读一些像“Eden”这样的概念时,我第一次真正意识到Java和JVM实际上可以在速度上击败C / C ++。 (每当C / C ++释放一个对象/内存块时,就会涉及代码......当Java释放一个对象时,它实际上根本不做任何事情;因为在良好的OO代码中,大多数对象几乎立即被创建和释放,这非常有效。)
现代GC往往非常高效,管理旧对象的方式与新对象大不相同,能够控制GC短而半,或者冗长彻底,并且命令行开关可以管理很多GC选项所以知道所有术语实际引用的内容实际上很有用。
注意:我刚刚意识到这是误导性的。 C ++的STACK分配速度非常快 - 我的观点是关于分配当前例程完成后能够存在的对象(我认为应该是所有对象 - 如果你要去,你应该不必考虑它在OO中思考,但在C ++速度可能会使这不切实际)。
如果你只是在堆栈上分配C ++类,那么它的分配将至少和Java一样快。
答案 4 :(得分:4)
Java收集任何无法访问的对象。如果其他任何内容都没有引用该条目,那么它将被收集,即使它有自己的引用。
答案 5 :(得分:4)
是Java垃圾收集器处理自引用!
How?
有一些称为垃圾收集根(GC根)的特殊对象。它们总是可以访问的,任何具有它们的对象都是可以访问的。
一个简单的Java应用程序具有以下GC根源:
要确定哪些对象不再使用,JVM会间歇性地运行非常适合称为标记和扫描算法的对象。它的工作原理如下
因此,如果无法从GC根目录访问任何对象(即使它是自引用或循环引用的话),它将进行垃圾回收。
答案 6 :(得分:2)
简单,是的。 :)
查看http://www.ibm.com/developerworks/java/library/j-jtp10283/
所有JDK(来自Sun)都有“达到能力”的概念。如果GC无法“到达”某个物体,它就会消失。
这不是任何“新”信息(您的第一个受访者很好),但链接很有用,简洁是甜蜜的。 :)