这是我最近在采访中被问到的一个问题:在'GC.Collect()'电话会议期间会收集哪些'随机'对象?
String a = new Random().Next(0, 1) ==1 ? "Whatever 1" : "Whatever 2";
String b = new WeakReference(new Random()).Target.Next(0, 1) == 1 ?
"Whatever 1" : "Whatever 2";
GC.Collect();
我回答说这是一个特定于实现的问题,它高度依赖于GC
实现和相应的弱引用语义。据我所知,C#规范没有提供GC.Collect
应该做什么的准确描述以及如何处理弱引用。
但是,我的采访者想听一些其他内容。
答案 0 :(得分:13)
Random()
个实例和WeakReference
都有资格收集:
Random
未存储在本地,更不用说稍后读取的本地。Random
已传递给WeakReference
,因此无论如何都可以收集 ,但WeakReference
本身没有任何地方,因此太有资格收集。没有字符串(这里只有2个字符串实例,而不是4个,即使达到了每个可能的代码路径):因为它们是c#代码中的文字,一旦存在就会被实现。
答案 1 :(得分:9)
确实这是依赖于实现(和编译器)的。如果所有这些都采用相同的方法,则无法知道哪些对象仍在堆栈中。由于堆栈上的对象仍然被引用,因此它们不可收集。
面试官希望你最有可能做的是在GC调用时检查哪些对象仍然可以访问.Collect假设一个“完美”的实现,尽快丢弃所有内容。
答案 2 :(得分:3)
然而,我的采访者想听别的东西。
我希望他们能够听到Marc Gravell在这里发布的答案,但这是基于过度简化的模型,该模型说明垃圾收集虚拟机的工作方式与现实无关。
例如,对GC.Collect
的调用可能会优化尾调用,在这种情况下,没有全局根,因此会收集所有堆分配的块。或者编译器可能会在堆栈帧上为每个临时(不仅仅是源代码中的变量)创建一个新条目,这样可以保持一切可达,并且不会收集任何内容。或者编译器可能会交换字符串a
和b
的创建顺序,并在Random
方法之前收集WeakReference
引用的Target
对象被调用导致null
引用异常,因此永远不会分配其他Random
。
答案 3 :(得分:1)
GC.Collect与Java相似,与System.gc()
相同它“建议”检查空值以删除它们。你不能真正依赖这个功能,因为它与C ++不同,它真的很自动。
希望它有所帮助!