垃圾收集器和循环引用
考虑这两个类:
public class A { B b; public A(B b) { this.b = b; } } public class B { A a; public B() { this.a = new A(this); } }
如果我有像上面这样devise的课程,垃圾收集员(GC)会收集这些课程的对象吗?
假设我这样做:
void f() { B b = new B(); }
在这个方法中,我创build了一个名为b
的B
实例,当方法返回时, b
超出范围,GC应该能够收集它,但是如果要收集它,则必须先收集第一个哪一个是B
的成员,而要收集a
,则需要先收集b
这个A
的成员。 它变成圆形。 所以我的问题是:这样的循环引用是为了防止GC收集对象?
- 如果是,那么我们如何避免这个问题呢? 我们如何确保在课堂devise中没有循环引用? 是否有任何工具(或编译器选项)可以帮助我们检测循环引用?
- 如果不是,我们在哪里以及为什么使用
WeakReference
类? 它的目的是什么?
.NET垃圾收集器可以绝对处理循环引用。 垃圾收集器如何工作的高层次的观点是…
- 从本地,静态和GC固定对象开始。 这些都不能收集
- 通过遍历这些对象的子对象来标记每个可以到达的对象
- 收集未标记的每个对象。
这样可以很好地收集循环引用。 只要它们中的任何一个都不能从已知不可收集的对象中得到,那么循环引用本质上是不相关的。
注:我意识到我已经遗漏了很多有趣的细节,以保持简单和直接的答案
不,这不会成为问题,因为GC可以处理循环引用
MSDN说
如果一组对象包含彼此的引用,但这些对象都不是直接或间接从堆栈或共享variables引用的,则垃圾回收将自动回收内存。
几个答案已经解释说循环引用不是问题。
至于弱引用 – 使用它们的原因是caching。
当GC遍历对象依赖树时,他忽略了弱引用。 换句话说,如果一个对象的唯一引用是一个弱对象,那么它将被垃圾收集,但是如果在创build引用和尝试使用引用之间没有垃圾收集,您仍然可以访问该对象。
没有那个循环引用不会影响垃圾收集器,并且它将完全能够收集到B的实例。
垃圾收集器知道在超出范围之后,没有人可以引用B的实例,因此,没有人可以使用B的实例来间接引用A.