这些对象中哪些有资格进行垃圾收集

本文关键字:有资格 对象 | 更新日期: 2023-09-27 18:15:08

这是我最近在面试中被问到的一个问题:哪些'随机'对象将在'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应该做什么以及如何处理弱引用的确切描述。

然而,我的面试官想听些别的。

这些对象中哪些有资格进行垃圾收集

Random()实例和WeakReference实例都有资格进行收集:

  • 第一个Random没有存储在本地,更不用说稍后读取的本地。
  • 第二个Random被传递给WeakReference,所以无论如何都可以收集,但是WeakReference 本身不在任何地方,因此有资格收集。

所有字符串都不是(这里只有2个字符串实例,而不是4个,即使到达了所有可能的代码路径):因为它们在c#代码中是字面量,它们一旦存在就会被拘禁。

这确实是依赖于实现(和编译器)的。如果所有这些都在同一个方法中,无法知道哪些对象仍在堆栈上。因为堆栈上的对象仍然是被引用的,所以它们不能被收集。

面试官最希望你做的是检查在GC调用时哪些对象仍然是可访问的。Collect假设一个"完美"的实现,可以尽快丢弃所有内容。

然而,我的面试官想听些别的。

我想他们想听到一个类似Marc Gravell在这里发布的答案,但那是基于一个过度简化的模型,关于垃圾收集虚拟机是如何工作的,与现实毫无相似之处。

例如,对GC.Collect的调用可能得到尾部调用优化,在这种情况下,没有全局根,因此收集所有堆分配的块。或者,编译器可能会为每个临时(不只是源代码中的变量)在堆栈框架上创建一个新条目,这使得所有内容都可以访问,并且不会收集任何内容。或者编译器可能会交换字符串ab的创建顺序,并在Target方法被调用之前收集WeakReference引用的Random对象,从而导致null引用异常,因此其他Random甚至永远不会被分配。

GC。Collect在Java中相当于System.gc()

它"建议"检查空值以删除它们。你不能真的依赖这个特性,因为它是自动的,不像c++。

希望有帮助!