方法本地 .NET 对象何时有资格进行 GC?

Jus*_*ant 5 .net c# garbage-collection memory-management large-object-heap

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

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

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

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

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

我的问题的核心是 .NET GC 对“此对象没有引用”的判断是否足够聪明,知道返回a后无法引用MethodThatReturns200mbObject(a)。尽管var a理论上仍可用于以后的代码,a但在方法第二行以下的任何地方都没有引用。理论上,编译器可以让 GC 知道它a是未引用的。但在实践中,我不确定它的行为方式。你知道吗?

Cha*_*thJ 1

这篇文章用例子解释了这一点。

\n\n

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

\n\n
\n

正确的答案是,这取决于项目配置\n 对象是否有资格在方法结束时\n 进行垃圾回收。正如在何时需要使用 GC.KeepAlive?\n 中所讨论的(它也简而言之地描述了 GC.KeepAlive \xe2\x80\x93 的用途,它\xe2\x80\x99s 是一种引用或\xe2 的方式\x80\x9cusing\xe2\x80\x9d 一个变量,确保\n优化器不会\xe2\x80\x99t优化使用),垃圾收集器可能\n决定在对象无法使用时立即收集对象不再执行任何\n 代码。在访问引用(在编译时)有效但尚未编写此类代码的情况下,很可能会发生这种情况。

\n\n

但是,在调试模式下编译和执行代码时,编译器会阻止这种情况发生以简化调试。因此,我们的测试方法的正确实现包括一个预处理器指令:

\n
\n\n

另一本好书《何时需要使用 GC.KeepAlive?》

\n