Java垃圾收集如何与循环引用一起使用?

问题

根据我的理解,如果没有其他东西"指向"该对象,Java中的垃圾收集会清除一些对象。

我的问题是,如果我们有这样的事情会发生什么:

class Node {
    public object value;
    public Node next;
    public Node(object o, Node n) { value = 0; next = n;}
}

//...some code
{
    Node a = new Node("a", null), 
         b = new Node("b", a), 
         c = new Node("c", b);
    a.next = c;
} //end of scope
//...other code

a,bc应该是垃圾收集,但它们都被其他对象引用。

Java垃圾收集如何处理这个问题? (或者它只是一个内存消耗?)


#1 热门回答(131 赞)

Java的GC认为对象是"垃圾",如果它们无法通过从垃圾收集根开始的链到达,那么将收集这些对象。尽管物体可以指向彼此形成一个循环,但如果它们从根部切断,它们仍然是垃圾。

有关详细信息,请参阅附录A:关于垃圾收集的真相741182407中有关无法访问的对象的部分。


#2 热门回答(109 赞)

是Java垃圾收集器处理循环引用!

How?

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

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

  • main方法中的局部变量
  • 主线程
  • 主类的静态变量

enter image description here

为了确定哪些对象不再使用,JVM间歇性地运行非常恰当地称为a标记和扫描算法.它的工作原理如下

  • 算法遍历所有对象引用,从GC根开始,并将每个找到的对象标记为活动。
  • 回收未被标记对象占用的所有堆内存。它只是标记为免费,基本上没有未使用的对象。

因此,如果无法从GC根目录访问任何对象(即使它是自引用或循环引用),它将进行垃圾收集。

当然,如果程序员忘记取消引用某个对象,有时会导致内存泄漏。

enter image description here

资料来源:Java Memory Management


#3 热门回答(10 赞)

垃圾收集器从一些始终被视为"可到达"的"根"位置开始,例如CPU寄存器,堆栈和全局变量。它的工作原理是找到这些区域中的任何指针,并递归地找到它们指向的所有内容。一旦找到所有这一切,每一个都是垃圾。

当然,有很多变化,主要是为了速度。例如,大多数现代垃圾收集器是"世代"的,意味着它们将对象分成几代,随着对象变老,垃圾收集器在它试图弄清楚该对象是否仍然有效的时间之间变得越来越长。 - 它开始假设如果它已经存在了很长时间,那么很可能会继续存活更长时间。

尽管如此,基本思想仍然是相同的:它都是基于从一些根本开始的东西开始,它仍然可以使用它,然后追逐所有指针以找到其他可能正在使用的东西。

有趣的是:人们常常会对垃圾收集器的这一部分与远程过程调用之类的对象的编组代码之间的相似程度感到惊讶。在每种情况下,你都是从一些根对象开始,并追逐指针来找到那些引用的所有其他对象......