class GCTest {
static Object r1;
static void Main() {
r1 = new Object();
Object r2 = new Object();
Object r3 = new Object();
System.GC.Collect(); // what can be reclaimed here ?
r1 = null;
r3.ToString();
System.GC.Collect(); // what can be reclaimed here ?
}
}
//代码 - DonBox的Essential .Net
答案 0 :(得分:3)
在第一行,没有对r2
的进一步引用,因此此对象可以在此处回收。在最后一行,为r1
创建的对象不再具有引用,并且局部变量r2
和r3
已完成,因此此时可以回收所有三个对象。但是,这将取决于它是如何编译的。
这三个都是根引用,因为没有其他内容引用它们。如果r1
是实例字段而不是静态字段,那么对GCTest
类的引用会使r1
引用不成为根引用。< / p>
答案 1 :(得分:2)
使用WeakReference尝试您的代码,当这些引用存活时,您将看到。尽量不要超出你的方法。 GC仅回收r1
。当您的引用失效时,WeakReference可以为您提供更好的洞察力。
有异常的回应当然是无稽之谈。 r3.ToString()
上升的唯一例外是空引用异常,但iff r3
为空。
答案 2 :(得分:2)
GC可以收集它可以证明的任何对象,它对应用程序没有任何影响。考虑它的一种方法是:对象永远分配 但只要确保你不能注意到它就允许实现回收内存。
在您的示例中,在第一个GC.Collect()
,第一个对象引用已写入r1
,r1
是一个静态变量,因此不知何故“永久”。从GC的角度来看,几乎任何代码都可以使用该静态变量,因此GC无法确保不会使用第一个对象。因此无法收集它。另一方面,第二个对象是用 local 变量编写的。局部变量仅限于方法代码(当方法退出时它会消失)并且GC能够注意到r2
将不再被使用(GC只需要查看方法,而不是整个代码,这是GC合理做的一部分)。因此,GC 可能收集第二个对象(此处没有义务)。
在第一个GC.Collect()
之后仍将使用第三个对象:调用其ToString()
方法。因此,GC不应该收集它。但是,可以想象VM注意到这是一个真实的Object
实例(不是任何其他类),内联对ToString()
的调用,并进一步得出结论:整个ToString()
调用是一种精心制作的无所事事的方式(没有明显的结果)。因此,GC 可能能够收集第三个对象并完全跳过ToString()
的呼叫。
当然,GC也可以免费收集东西。 GC的全部意义在于它“在幕后”运行,而不会影响代码执行(在最终确定的情况下这并不完全正确,但这是一个额外的复杂层,在掌握基础知识之前不应该设想)
威尔逊的article对于任何想要了解垃圾收集的人来说确实是必读的。
答案 3 :(得分:0)
对我而言,它意味着参考链中的第一个对象。即A指的是B,B指的是C等.A是根,因为没有别的指代它。
在第一个。
r1是静态的并且GC测试持有对它的引用因此无法收集,而r2可以被收集。 r3将是除非你在调试器或GC.KeepAlive被称为
在第二个
r1可以收集,因为它不再在范围内 r2已经收集完毕 并且取决于是否收集了r3,它可能会引发异常,或者会被收集。
答案 4 :(得分:0)
答案 5 :(得分:0)
虽然我无法详细解答您的问题,但我可以向您指出一篇关于垃圾收集技术的好文章:
Paul R. Wilson (1994):单处理器垃圾收集技术
如果我没记错的话,它包含根引用的定义。