方法本地.NET对象何时符合GC条件?

时间:2017-07-21 00:22:55

标签: c# .net memory-management garbage-collection large-object-heap

假设我有一个像这样的C#方法:(显然不是真正的代码)

byte[] foo()
{
    var a = MethodThatReturns500mbObject();
    var b = MethodThatReturns200mbObject(a);
    byte[] c = MethodThatReturns150mbByteArray(b);
    byte[] d = UnwiselyCopyThatHugeArray(c);
    return d;
}

正如你可以通过命名猜测的那样,这些方法返回的对象是巨大的。每个需要数百兆的RAM,尽管前两个对象由数百万个较小的对象组成,而不是像后两个数组那样的一个巨大的块。

我们很快就会将其优化为流式处理解决方案,但与此同时,我想确保至少我们在执行代码时不会阻止GC的早期对象产生后来的对象。

我的问题是:一旦MethodThatReturns200mbObject(a)返回,对象a是否有资格获得GC?如果没有,那么让GC知道有500MB存在等待它的最佳方式是什么?

我的问题的核心是.NET GC是否确定了这个对象没有引用"足够聪明,知道在a返回后无法引用MethodThatReturns200mbObject(a)。即使var a在理论上仍适用于以后的代码,a也不会在方法的第二行以下的任何地方引用。理论上,编译器可以让GC知道a未被引用。但在实践中,我不确定它的表现如何。你知道吗?

1 个答案:

答案 0 :(得分:1)

This post explains it with examples.

理论上,编译器可以让GC知道a是未引用的。但在实践中,我不确定它的表现如何。你知道吗?

  

正确的答案是它取决于项目配置   该对象是否有资格在最后进行垃圾回收   方法。正如我什么时候需要使用GC.KeepAlive?   (这也描述了GC.KeepAlive的目的 - 简而言之,它是一个   引用或“使用”变量的方式确保   优化器不会优化使用率,垃圾收集器可能   决定在任何物品无法使用时立即收集物品   再执行代码。这种情况很可能发生在以下情况中   访问引用(在编译时)是有效的,但不是这样   代码已写完。

     

但是,在Debug-mode中编译和执行代码时,编译器   防止这种情况发生以简化调试。结果,   我们的测试方法的正确实现包括一个预处理器   指令:

另一个好读When do I need to use GC.KeepAlive?