垃圾收集器和循环引用

时间:2012-01-12 18:46:08

标签: c# garbage-collection circular-reference

考虑这两个类:

public class A
{
     B b;
     public A(B b) { this.b = b; }
}

public class B
{
     A a;
     public B() { this.a =  new A(this); }
}

如果我有类似上面设计的类,那么垃圾收集器(GC)会收集这些类的对象吗?

假设我这样做:

void f()
{
     B b = new B();
}

在这个方法中,我创建了一个名为B的{​​{1}}实例,当方法返回时,b超出范围,GC应该能够收集它,但如果要收集它,则必须首先收集b成为a的成员,并收集B,它需要首先收集ab的成员。它变成了圆形。所以我的问题是:这样的循环引用会阻止GC收集对象吗?

  • 如果是,那我们怎样才能避免这个问题呢?我们怎样才能确保在课堂设计中没有循环参考?是否有任何工具(或编译器选项)可以帮助我们检测循环引用?
  • 如果不是,我们在哪里以及为什么要使用WeakReference课程?它的目的是什么?

4 个答案:

答案 0 :(得分:84)

.Net垃圾收集器绝对可以处理循环引用。关于垃圾收集器如何工作的非常高级视图是......

  • 从本地,静态和GC固定对象开始。这些都不能收集
  • 通过遍历这些对象的子项来标记可以到达的每个对象
  • 收集每个未标记的对象。

这样可以很好地收集循环引用。只要从已知无法收集的对象中找不到它们,那么循环引用基本上是无关紧要的。

注意:我意识到我遗漏了许多有趣的细节,以便让这个答案变得简单直接

答案 1 :(得分:30)

不,这不会有问题,因为GC可以处理循环引用

MSDN说

  

如果一组对象包含彼此的引用,但没有引用   这些对象   直接或间接地从堆栈或共享变量引用,然后是垃圾   集合将自动回收内存。

答案 2 :(得分:5)

没有那个循环引用不会影响垃圾收集器,它将完全能够收集B的实例。

垃圾收集器知道没有人可以在超出范围后引用B的实例,因此,没有人可以使用B的实例来间接引用A.

答案 3 :(得分:5)

已经解释了几个答案,循环引用不是问题。

对于弱引用 - 使用它们的原因是缓存。

当GC遍历对象依赖关系树时,他忽略了弱引用。换句话说,如果对象的唯一引用是弱对象,则它将被垃圾收集,但如果在引用创建和您尝试使用之间没有垃圾收集,您仍然可以访问该对象。