关于C#:垃圾收集器和循环引用

Garbage collector and circular reference

考虑以下两类:

1
2
3
4
5
6
7
8
9
10
11
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)收集吗?

假设我这样做:

1
2
3
4
void f()
{
     B b = new B();
}

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

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


.Net垃圾收集器可以绝对处理循环引用。垃圾收集器的工作原理非常高级的观点是...

  • 从局部变量,静态变量和GC固定对象开始。这些都无法收集
  • 标记遍历这些对象的子对象可以到达的每个对象
  • 收集每个未标记的对象。

这样就可以很好地收集循环引用。只要从已知无法收集的对象都无法到达它们,则循环引用实质上是无关紧要的。

注意:我意识到我已经省略了许多有趣的细节,以使此答案简单直接


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

MSDN说

If a group of objects contain references to each other, but none of
these object
are referenced directly or indirectly from stack or shared variables, then garbage
collection will automatically reclaim the memory.


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

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

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


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

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