Java中的垃圾收集问题

Java中的垃圾收集问题,java,garbage-collection,Java,Garbage Collection,假设我有一个双链接列表。我这样创建它: MyList list = new MyList(); 然后我添加一些节点,使用它,然后决定像这样扔掉旧列表: list = new MyList(); 因为我刚刚创建了一个新列表,所以旧内存区域中的节点仍然相互指向。这是否意味着具有旧节点的区域不会被垃圾收集?我是否需要使每个节点都指向null,这样它们就可以被GC’d?不需要。JavaGC可以很好地处理循环引用 从概念上讲,每次GC运行时,它都会查看系统中的所有“活动”根引用: 每个堆栈帧中的局部

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

MyList list = new MyList();
然后我添加一些节点,使用它,然后决定像这样扔掉旧列表:

list = new MyList();

因为我刚刚创建了一个新列表,所以旧内存区域中的节点仍然相互指向。这是否意味着具有旧节点的区域不会被垃圾收集?我是否需要使每个节点都指向null,这样它们就可以被GC’d?

不需要。JavaGC可以很好地处理循环引用

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

  • 每个堆栈帧中的局部变量
  • “this”在每个实例方法堆栈框架中引用
  • 实际上,所有静态变量(事实上,它们实际上是由
    Class
    对象引用的,而
    ClassLoader
    s又引用这些对象,但我们暂时忽略它们。)
对于那些“已知活动”对象,它将检查其中的字段,并将其添加到列表中。它递归到那些被引用的对象中,依此类推,直到找到系统中的每个活动对象。然后,它会把所有它认为不存在的东西都垃圾收集起来

循环引用的节点相互引用,但没有活动对象引用它们,因此它们符合垃圾收集的条件


请注意,这是对垃圾收集器在概念上如何工作的一个非常简化的总结。实际上,它们非常复杂,有生成、压缩、并发性等问题。

垃圾收集器查找没有在任何地方引用的对象。 因此,如果您创建了一个对象,并且像下面的示例一样丢失了引用,垃圾收集器将收集该引用。

否——Java(至少在正常实现时)不使用引用计数,而是使用真正的垃圾收集器。这意味着(本质上)当它耗尽内存时,它会查看堆栈上、寄存器中以及其他始终可以访问的位置上的指针,并“跟踪”它们,以找到可以从它们访问的所有内容


其他数据结构(如双链接列表)中的指针并不重要,除非有外部指针(可访问)指向它们。

不,GC将以任何方式回收它们,因此您不需要将它们指向null。这里有一段很好的JavaWorld描述:

任何垃圾收集算法都必须 做两件基本的事情。首先,它必须 检测垃圾对象。第二,它 必须回收所使用的堆空间 垃圾的对象,并使它 可供该计划使用。垃圾 检测通常是完成的 通过定义一组根和 从网络确定可达性 根。如果存在,则对象是可访问的 是来自 执行程序的根 可以访问该对象。根是 始终可访问该程序。任何 可从中访问的对象 根被认为是活的。物体 将考虑无法到达的 垃圾,因为他们不能再 影响课程的未来进程 执行


垃圾收集器查看对象是否由活动线程引用。如果任何活动线程都无法访问对象,则它们有资格进行垃圾收集


对象是否相互引用并不重要。

正如其他人所指出的,Java垃圾收集器不只是查看引用计数;相反,它主要查看一个图,其中节点是当前存在的对象,链接是从一个对象到另一个对象的引用。它从一个已知为活动的节点(例如主方法)开始,然后垃圾收集任何无法访问的内容


讨论了实现这一点的各种方法,尽管我不知道任何JVM实现都使用哪种方法。

如果您创建了自己的双链接列表,并将其放入双链接列表容器(包含列表中的项目);只有这些容器彼此链接

因此,在您的列表中,将有一个对象A包含在A'中。A'链接到B'和B'是一个容器,其中包含B等,并且任何对象都不必引用另一个对象

在正常情况下,这些容器不能从外部获得(只有内容是有趣的);因此,只有您的列表才会引用您的容器(请记住,您的内容并不知道他的容器)

如果您删除对列表的最后引用(列表,而不是容器或内容),GC将尝试收集列表内容,即您的容器和内容

由于您的容器在外部不可用,因此它们的唯一引用是彼此和主列表。所有这些都被称为隔离岛。关于内容,如果它们在您的应用程序中仍然有引用,它们将在GC中生存,如果没有,它们将不会

因此,当您删除列表时,只有A'和B'将被删除,因为即使它们仍然有引用,这些引用也是孤岛的一部分。如果A和B没有更多的参考,它们也将被删除。

可能的重复请参见: