假设我有一个双向链表。我这样创建它:
MyList list = new MyList();
然后我添加一些节点,使用它然后决定丢弃这样的旧列表:
list = new MyList();
由于我刚刚创建了一个新列表,旧内存区域内的节点仍然指向彼此。这是否意味着旧节点的区域不会被垃圾收集?我是否需要将每个节点指向null以便它们是GC?
答案 0 :(得分:12)
不,你没有。 Java GC处理循环引用就好了。
从概念上讲,每次GC运行时,它都会查看系统中的所有“实时”根引用:
Class
个对象引用,而这些对象又由ClassLoader
引用,但暂时忽略它们。)使用那些“已知的实时”对象,它会检查其中的字段,并添加到列表中。它会递归到那些引用的对象,依此类推,直到找到系统中的每个活动对象。然后垃圾收集没有认为是活的所有内容。
您的循环引用节点互相引用,但没有活动对象引用它们,因此它们有资格进行垃圾回收。
请注意,这是一个粗略简化的垃圾收集器概念的工作原理摘要。实际上,它们非常复杂,包括代,压缩,并发问题等。
答案 1 :(得分:1)
如果您创建了自己的双链表,并且放入了这个双链表容器(包含列表中的项);只有那些容器相互链接。
因此,在您的列表中,您将拥有A'中包含的对象A. A'与B'相关联,B'是容纳B等的容器。没有任何对象必须引用另一个。
在正常情况下,这些容器将无法从外部获取(只有内容很有趣);因此,只有您的列表会引用您的容器(请记住您的内容不知道他的容器)。
如果您删除了对列表的最后一个引用(列表,而不是容器或内容),GC将尝试收集您的列表内容,这是您的容器和内容。
由于您的容器在唯一的引用之外不可用,因此它们彼此之间是一个主列表。所有这一切都被称为隔离岛。关于内容,如果他们仍然在您的申请中有参考,他们将在GC中存活,如果不是,他们将不会。
因此,当您删除列表时,只会删除A'和B',因为即使它们仍然有引用,这些引用也是岛屿的一部分。如果A和B没有更多的引用,它们也将被删除。
答案 2 :(得分:0)
否 - Java(至少正常实现)不使用引用计数,它使用真正的垃圾收集器。这意味着(实质上)当内存耗尽时,它会查看堆栈上的指针,寄存器以及其他始终可访问的位置,并“追踪”它们以查找可从中访问的所有内容。
其他数据结构中的指针(如双向链表)根本无关紧要,除非有一些外部指针(可访问)导致它们。
答案 3 :(得分:0)
不,GC无论如何都会收回它们,所以你不需要将它们指向null。这是JavaWorld article中的一个很好的段落描述:
任何垃圾收集算法都必须 做两件基本的事。首先,它必须 检测垃圾对象。第二,它 必须回收使用的堆空间 垃圾对象并制作它 可用于该计划。垃圾 检测通常是完成的 通过定义一组根和 从中确定可达性 根。如果存在,则可以访问对象 是一些参考的路径 执行程序的根源 可以访问该对象。根源是 始终可以访问该程序。任何 可以从中获取的对象 根被认为是活的。对象 考虑不可达的 垃圾,因为他们不能再 影响未来的课程 执行。
答案 4 :(得分:0)
垃圾收集器查看实时线程是否引用了对象。如果任何活动线程无法访问对象,则它们有资格进行垃圾回收。
对象是否相互引用无关紧要。
答案 5 :(得分:0)
正如其他人所指出的那样,Java垃圾收集器并不只是看引用计数;相反,它主要查看一个图表,其中节点是当前存在的对象,链接是从一个对象到另一个对象的引用。它从一个已知的实时节点(例如主方法)开始,然后垃圾收集任何无法到达的节点。
The Wikipedia article on garbage collection讨论了可以这样做的各种方法,尽管我不确切知道任何JVM实现使用了哪种方法。
答案 6 :(得分:-1)
垃圾收集器查找未在任何位置引用的对象。 因此,如果您创建一个对象并且像示例一样丢失了引用,垃圾收集器将收集它。