【问题标题】:When are method local .NET objects eligible for GC?方法本地 .NET 对象何时符合 GC 条件?
【发布时间】:2017-12-26 21:10:03
【问题描述】:

假设我有一个像这样的 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 未被引用。但在实践中,我不确定它的行为方式。你知道吗?

【问题讨论】:

  • GC.KeepAlive() 如果所有变量在其作用域结束前都已保持活动状态,则不会有太大用处。
  • 在发布模式下,是的,编译器足够聪明,可以在不再使用 a 时将其标记为垃圾回收的候选对象。 This answer 也可能有用

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


【解决方案1】:

This post explains it with examples.

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

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

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

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

【讨论】:

  • 链接的答案是一本很好的读物,正是我想要的。谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多