垃圾收集器和循环引用

问题描述 投票:0回答:5

考虑这两个类:

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
b
实例,当该方法返回时,
b
超出范围,GC 应该能够收集它,但如果它要收集它,它必须首先收集
a
,它是
B
的成员,而要收集
a
,它需要首先收集
b
,它是
A
的成员。它变成圆形。所以我的问题是:这样的循环引用会阻止 GC 收集对象吗?

  • 如果是的话,我们该如何避免这个问题呢?我们如何确保我们的类设计中没有循环引用?有没有任何工具(或编译器选项)可以帮助我们检测循环引用?
  • 如果不是,我们在哪里以及为什么使用
    WeakReference
    类?它的目的是什么?
c# garbage-collection circular-reference
5个回答
110
投票

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

  • 从局部变量、静态变量和 GC 固定对象开始。这些都收集不到
  • 标记通过遍历这些对象的子对象可以到达的每个对象
  • 收集所有未标记的物品。

这允许很好地收集循环引用。只要它们都无法从已知不可收集的对象访问,那么循环引用本质上是无关紧要的。

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


39
投票

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

MSDN 说

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


7
投票

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

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

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


6
投票

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

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


0
投票

刚刚发现 GC 在某些情况下处理循环引用并不是那么好......

使用 WeakReference 无论如何都会造成死胡同。

从 C++ 开始,GC 之路崎岖不平。 在 C++ 中,唯一指针和共享指针更加强大。 GC 没问题,但是……嗯……:)

© www.soinside.com 2019 - 2024. All rights reserved.