23

希望是一个简单的问题。以循环链表为例:

class ListContainer
{
  private listContainer next;
  <..>

  public void setNext(listContainer next)
  {
    this.next = next;
  }
}

class List
{
  private listContainer entry;
  <..>
}

现在因为它是一个循环链表,当添加一个元素时,它在它的下一个变量中有一个对自身的引用。删除列表中的唯一元素时,条目设置为 null。是否需要将 ListContainer.next 设置为 null 以及垃圾收集器释放它的内存还是自动处理这种自引用?

4

7 回答 7

24

仅依靠引用计数的垃圾收集器通常容易无法收集此类自引用结构。这些 GC 依赖于对对象的引用数的计数,以计算给定对象是否可访问。

非引用计数方法应用更全面的可达性测试来确定对象是否有资格被收集。这些系统定义了一个总是被认为是可达的对象(或一组对象)。可以从此对象图中获得引用的任何对象都被认为不符合收集条件。不能从该对象直接访问的任何对象都不是。因此,循环不会最终影响可达性,并且可以被收集。

另请参阅有关跟踪垃圾收集器的 Wikipedia 页面。

于 2009-01-02T20:14:19.553 回答
14

如果您依靠计数引用来确定对象是否已死,则循环引用是一个(可解决的)问题。没有java实现使用引用计数,AFAIK。较新的 Sun JRE 混合使用了几种类型的 GC,我认为都是标记和清除或复制。

例如,您可以在Wikipedia上阅读有关垃圾收集的更多信息,并在此处此处阅读有关 java GC 的一些文章。

于 2009-01-02T19:57:25.190 回答
7

对此的实际答案取决于实现。Sun JVM 会跟踪一些根对象(线程等),当它需要进行垃圾回收时,会从这些对象中找出可以访问的对象并保存它们,丢弃其余对象。允许一些优化实际上比这更复杂,但这是基本原则。这个版本不关心循环引用:只要没有活对象持有对死对象的引用,它就可以被 GC。

其他 JVM 可以使用一种称为引用计数的方法。当创建对对象的引用时,一些计数器会增加,当引用超出范围时,计数器会减少。如果计数器达到零,则对象被最终确定并被垃圾收集。然而,这个版本确实允许循环引用永远不会被垃圾收集。作为一种保护措施,许多这样的 JVM 包括一个备份方法来确定哪些对象实际上是死的,它会定期运行以解决自引用和对堆进行碎片整理。

于 2009-01-02T20:19:43.273 回答
6

作为一个非答案(现有答案已经足够了),如果您对 GC 完全感兴趣,您可能需要查看有关 JVM 垃圾收集系统的白皮书。(任何,只是谷歌 JVM 垃圾收集)

我对其中使用的一些技术感到惊讶,并且在阅读诸如“伊甸园”之类的一些概念时,我第一次真正意识到 Java 和 JVM 实际上可以在速度上击败 C/C++。(每当 C/C++ 释放一个对象/内存块时,都会涉及到代码......当 Java 释放一个对象时,它实际上什么都不做;因为在良好的 OO 代码中,大多数对象几乎是立即创建和释放的,这非常有效。)

现代 GC 往往非常高效,管理旧对象与新对象大不相同,能够控制 GC 短而半,长而彻底,并且许多 GC 选项可以通过命令行开关管理,因此实际上了解所有术语实际指的是什么很有用。

注意:我刚刚意识到这是误导。C++ 的 STACK 分配非常快——我的意思是分配在当前例程完成后能够存在的对象(我相信应该是所有对象——如果你打算这样做,你不应该考虑在 OO 中思考,但在 C++ 中的速度可能会使这不切实际)。

如果您只是在堆栈上分配 C++ 类,它的分配将至少与 Java 一样快。

于 2009-01-02T22:38:51.480 回答
4

Java 收集任何不可访问的对象。如果没有其他东西引用该条目,那么它将被收集,即使它具有对自身的引用。

于 2009-01-02T19:57:09.900 回答
4

是的 Java 垃圾收集器处理自引用!

How?

有称为垃圾收集根(GC 根)的特殊对象。这些总是可以访问的,任何以它们为根的对象也是如此。

一个简单的 Java 应用程序具有以下 GC 根:

  1. main方法中的局部变量
  2. 主线程
  3. 主类的静态变量

在此处输入图像描述

为了确定哪些对象不再使用,JVM 会间歇性地运行一种非常恰当地称为标记和清除算法的方法。它的工作原理如下

  1. 该算法遍历所有对象引用,从 GC 根开始,并将找到的每个对象标记为活动的。
  2. 所有未被标记对象占用的堆内存都会被回收。它被简单地标记为空闲,基本上清除了未使用的对象。

因此,如果任何对象无法从 GC 根访问(即使它是自引用或循环引用的),它将受到垃圾回收。

于 2013-08-21T06:54:05.127 回答
2

简单地说,是的。:)

查看http://www.ibm.com/developerworks/java/library/j-jtp10283/

所有 JDK(来自 Sun)都有“可达性”的概念。如果 GC 不能“到达”一个对象,它就会消失。

这不是任何“新”信息(您对受访者的第一个信息很棒),但链接很有用,简洁是甜蜜的。:)

于 2009-01-02T22:18:23.500 回答