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

When are method local .NET objects eligible for GC?

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

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

正如您从命名中可以猜到的那样,这些方法返回的对象是巨大的。尽管前两个对象由数百万个较小的对象组成,而不是像后两个数组那样由一个大块组成,但每个对象总共需要数百兆字节的 RAM。

我们很快会将其优化为流解决方案,但与此同时我想确保至少我们不会在执行代码以生成较晚对象时阻止较早对象的 GC .

我的问题是:一旦 MethodThatReturns200mbObject(a) returns,对象 a 是否符合 GC 条件?如果没有,让 GC 知道有 500MB 的礼物等待它的最佳方法是什么?

我问题的核心是.NET GC对"this object has no references"的判断是否足够聪明,知道MethodThatReturns200mbObject(a)returns之后不能引用a。尽管 var a 理论上仍可用于以后的代码,但 a 未在该方法第二行以下的任何位置引用。理论上,编译器可以让 GC 知道 a 未被引用。但在实践中,我不确定它的行为方式。你知道吗?

This post explains it with examples.

理论上,编译器可以让 GC 知道 a 未被引用。但在实践中,我不确定它的行为方式。你知道吗?

The correct answer is that it depends on the project configuration whether the object will be eligible for garbage collection at the end of the method. As discussed in When do I need to use GC.KeepAlive? (which also describes the purpose of GC.KeepAlive – in short, it’s a way of referencing or “using” a variable making sure that the optimizer won’t optimize the usage away), the garbage collector might decide to collect objects as soon as they are not usable by any executing code anymore. This can very well happen in situations where it would be valid to access a reference (at compile time), but no such code has been written.

However, when compiling and executing code in Debug-mode, the compiler prevents this from happening to ease debugging. As a result, the correct implementation of our test method includes a preprocessor directive:

又一本好书When do I need to use GC.KeepAlive?