可以强制对象在Gen 1或Gen 2中而不是在Gen 0中进行垃圾回收吗?

时间:2015-05-18 11:38:34

标签: c# .net garbage-collection garbage

一位采访者问我一个奇怪的问题,我无法找到答案。

  

是否可以强制对象在Gen 1或Gen 2中进行垃圾回收而不是在Gen 0中?

3 个答案:

答案 0 :(得分:5)

你不能......但是你可以延长物体的寿命直到某一点。方法中最简单的方法是:

var myObject = new MyObject();

... some code
... some other code

// The object won't be colleted until this point **at least**
GC.KeepAlive(myObject)

或者您可以使用GCHandle

var myObject = new MyObject();
this.Handle = GCHandle.Alloc(new object(), GCHandleType.Normal);

(其中this.Handle是对象的字段)

也许在另一种方法中:

this.Handle.Free();

GCHandleType.Normal的说明是:

  

您可以使用此类型跟踪对象并防止垃圾收集器对其进行收集。当非托管客户端将唯一一个从垃圾收集器无法检测到的引用保存到托管对象时,此枚举成员非常有用。

请注意,如果您在GCHandle内执行此操作(class"此"),则应实施IDisposable模式以释放this.Handle }。

好的......技术上你可以:

var myObject = new MyObject();
GC.Collect(0); // collects all gen0 objects... Uncollected gen0 objects become gen1
GC.KeepAlive(myObject);

现在myObject是gen1 ......但这并没有真正解决你的问题: - )

答案 1 :(得分:5)

public class WillAlwaysBeCollectedInGen1or2
{
  ~WillAlwaysBeCollectedInGen1or2()
  {
  }
}

因为它有一个终结者,并且没有任何代码可以调用GC.SuppressFinalize(this),所以它总是会在最终确定队列中结束而不是在它首次符合收集条件时被收集,这意味着它将始终被收集在第一代以外的一代人中。

当然,由于我们通常希望发生相反的事情(尽快收集对象),这说明为什么不应该定义终结者,除非实际需要,并且应该总是调用GC.SuppressFinalize(this)如果一个物体处于最终化没有做任何有用的状态(最明显的是,如果它已被明确处理,但可能存在其他情况)。

因此,这种知识的用处是这样的;知道什么不该做。

通过扩展,您可以强制在Gen1或Gen2中收集任意对象,方法是在这样的对象中保留对它的强引用:

public class PreventGen0Collection
{
  private object _keptAlive;
  public PreventGen0Collection(object keptAlive)
  {
    _keptAlive = keptAlive;
  }
  ~PreventGen0Collection()
  {
  }
}

因为PreventGen0Collection本身被阻止收集,直到至少第1代,如上所述,传递给其构造函数的对象甚至不能在GC扫描中被收集,因此将被提升为下一代。

再次,这演示了要避免的代码;最终可能导致不仅仅是一个被提升的对象,而是一个完整的图形。不要在不需要的情况下使用终结者,并在可能的情况下禁止终结。

答案 2 :(得分:4)

根据GC.Collect的文件:

  

强制所有世代立即进行垃圾收集。

然后是的,你可以做到。只需强制收集。

如此处所述,Fundamentals of Garbage Collection,生存和促销活动:

  

垃圾收集中未回收的对象称为幸存者,并被提升为下一代。

因此,如果在强制收集之前对象在第0代中,它现在将在第1代中。

好的,然后,如果我不再引用该对象该怎么办?如果我强制收集那会怎么样?好吧,很可能会被收集。可以修复吗?好吧,取决于你的意思"固定",但是是。

为对象添加终结器。终结器将使对象在收集期间移动到单独的列表,准备好终结器线程完成它。只有在终结者处理之后,它才有资格收集,但到那时它已经被提升了。

另请注意,如果您添加终结器,因为您需要处理没有引用的情况,您不再需要强制收集,因为这是一个非常具体的面试问题问题,你现在已经保证它将在第0代幸存下来。

这两个步骤,其中任何一个都可以保证在第0代不收集对象:

  1. 添加终结者
  2. 等待对象的引用并强制收集。
  3. 警告:记录了垃圾收集,但在.NET生命周期中已经调整了各种方式和时间。是否可以将文档和上面的文本作为文档修复,或者是否在此处进行了优化,例如可以使GC.Collect 强制收集,因为集合已在进行中我不会&# 39;不知道。

    既然你在面试中提到我会说上面应该是你对面试官的答案,但在实践中不要依赖这些。

    GUIDELINE :依赖垃圾收集器的内部是制作脆弱代码的一种方法。

    不要做

    我唯一能看到实际搞乱GC.Collect的好理由,甚至在那里它是可疑的,是在一个或多或少的单线程系统中大批量处理。例如,定期处理大批量数据的Windows服务可以执行一个批处理,然后强制集合减少内存占用,直到下一批到期为止。

    然而,这是一个高度专业化的案例。除了满足面试官之外,GC.Collect不应(作为指导原则)出现在您的生产代码中。