关于Java中垃圾收集的问题

时间:2010-08-17 19:43:14

标签: java garbage-collection

假设我有一个双向链表。我这样创建它:

MyList list = new MyList();

然后我添加一些节点,使用它然后决定丢弃这样的旧列表:

list = new MyList();

由于我刚刚创建了一个新列表,旧内存区域内的节点仍然指向彼此。这是否意味着旧节点的区域不会被垃圾收集?我是否需要将每个节点指向null以便它们是GC?

7 个答案:

答案 0 :(得分:12)

不,你没有。 Java GC处理循环引用就好了。

从概念上讲,每次GC运行时,它都会查看系统中的所有“实时”根引用:

  • 每个堆栈框架中的局部变量
  • “this”在每个实例中引用方法堆栈框架
  • 实际上,所有静态变量(实际上这些变量都由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)

垃圾收集器查找未在任何位置引用的对象。 因此,如果您创建一个对象并且像示例一样丢失了引用,垃圾收集器将收集它。