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
s又引用这些对象,但我们暂时忽略它们。)ClassLoader
请注意,这是对垃圾收集器在概念上如何工作的一个非常简化的总结。实际上,它们非常复杂,有生成、压缩、并发性等问题。垃圾收集器查找没有在任何地方引用的对象。 因此,如果您创建了一个对象,并且像下面的示例一样丢失了引用,垃圾收集器将收集该引用。否——Java(至少在正常实现时)不使用引用计数,而是使用真正的垃圾收集器。这意味着(本质上)当它耗尽内存时,它会查看堆栈上、寄存器中以及其他始终可以访问的位置上的指针,并“跟踪”它们,以找到可以从它们访问的所有内容
其他数据结构(如双链接列表)中的指针并不重要,除非有外部指针(可访问)指向它们。不,GC将以任何方式回收它们,因此您不需要将它们指向null。这里有一段很好的JavaWorld描述: 任何垃圾收集算法都必须 做两件基本的事情。首先,它必须 检测垃圾对象。第二,它 必须回收所使用的堆空间 垃圾的对象,并使它 可供该计划使用。垃圾 检测通常是完成的 通过定义一组根和 从网络确定可达性 根。如果存在,则对象是可访问的 是来自 执行程序的根 可以访问该对象。根是 始终可访问该程序。任何 可从中访问的对象 根被认为是活的。物体 将考虑无法到达的 垃圾,因为他们不能再 影响课程的未来进程 执行
垃圾收集器查看对象是否由活动线程引用。如果任何活动线程都无法访问对象,则它们有资格进行垃圾收集
对象是否相互引用并不重要。正如其他人所指出的,Java垃圾收集器不只是查看引用计数;相反,它主要查看一个图,其中节点是当前存在的对象,链接是从一个对象到另一个对象的引用。它从一个已知为活动的节点(例如主方法)开始,然后垃圾收集任何无法访问的内容
讨论了实现这一点的各种方法,尽管我不知道任何JVM实现都使用哪种方法。如果您创建了自己的双链接列表,并将其放入双链接列表容器(包含列表中的项目);只有这些容器彼此链接 因此,在您的列表中,将有一个对象A包含在A'中。A'链接到B'和B'是一个容器,其中包含B等,并且任何对象都不必引用另一个对象 在正常情况下,这些容器不能从外部获得(只有内容是有趣的);因此,只有您的列表才会引用您的容器(请记住,您的内容并不知道他的容器) 如果您删除对列表的最后引用(列表,而不是容器或内容),GC将尝试收集列表内容,即您的容器和内容 由于您的容器在外部不可用,因此它们的唯一引用是彼此和主列表。所有这些都被称为隔离岛。关于内容,如果它们在您的应用程序中仍然有引用,它们将在GC中生存,如果没有,它们将不会 因此,当您删除列表时,只有A'和B'将被删除,因为即使它们仍然有引用,这些引用也是孤岛的一部分。如果A和B没有更多的参考,它们也将被删除。可能的重复请参见: