假设我有一个像这样的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
未被引用。但在实践中,我不确定它的表现如何。你知道吗?
答案 0 :(得分:1)
This post explains it with examples.
理论上,编译器可以让GC知道a是未引用的。但在实践中,我不确定它的表现如何。你知道吗?
正确的答案是它取决于项目配置 该对象是否有资格在最后进行垃圾回收 方法。正如我什么时候需要使用GC.KeepAlive? (这也描述了GC.KeepAlive的目的 - 简而言之,它是一个 引用或“使用”变量的方式确保 优化器不会优化使用率,垃圾收集器可能 决定在任何物品无法使用时立即收集物品 再执行代码。这种情况很可能发生在以下情况中 访问引用(在编译时)是有效的,但不是这样 代码已写完。
但是,在Debug-mode中编译和执行代码时,编译器 防止这种情况发生以简化调试。结果, 我们的测试方法的正确实现包括一个预处理器 指令: