3

在我的应用程序中,我有一个每隔几秒钟创建一次的大对象。我用它做一些工作,然后我不再需要它了。

我在任务管理器中看到,即使我没有对该对象的任何引用并且需要收集它,ram 的大小也会增加。

实施后IDisposable,ram 立即下降。

为什么是这样?我没有这样做GC.Collect,我只是释放了对象并告诉 GC 它不需要为我的对象调用终结器。

编辑:

这是我用于IDisposable对象的代码:

public void Dispose()
{
  base.Dispose();
  Dispose(true);
  GC.SuppressFinalize();
}

private void Dispose(bool disposing)
{
  //here i release unmanaged resources
  if (disposing)
  {
    //here i release all managed resources
  }
}

~MyObject()
{
  Dispose(false);
}

在我的大对象中,我myObject.Dispose();不再需要它之后再做。

我的问题不是关于如何实现IDisposable或 GC 一般如何工作。我只是想知道当我自己处理对象或让 GC 完成它的工作时会有什么不同。

4

4 回答 4

1

正如@Steven 在他的评论中指出的那样,IDisposable 是 CLR 不关心的。通过实现它,您只需告诉对象的使用者在不再需要对象时调用其 Dispose 方法。在内存管理方面,您可以为此编写自己的接口,例如 IDisposable2,并获得相同的技术效果。然而,这将是一件愚蠢的事情,因为.net 开发人员应该知道在不再需要对象时调用 idisposable.dispose。此外,该接口有内置语言 (c#) 支持(使用 {...})。

你写“我试图实现 IDisposable,然后 ram 立即下降。”

重要的是你的“实施”做了什么。那里的代码应该清理非托管代码、Windows 资源等。

于 2012-07-06T09:27:42.223 回答
0

.NET 内存不像往常一样有 2 种状态(已使用和未使用),但实际上是 4:(A)由活动对象使用,(B)由死对象使用,(C)不被任何对象使用,但被框架和 (D) 未使用。

当你创建一个对象时,Framework 会首先尝试使用 C 类的内存,如果它没有足够的可用空间,它会向操作系统询问一些类型 (D) 的内存,并将其转换为(C) 然后将其用于您的对象。

当一个对象超出范围时,它将从 (A) 下降到 (B),在下一次垃圾运行时,它将从 (B) 下降到 (C) 或 (D)。这在很大程度上取决于内部结构(想想内存碎片和朋友)、内存压力和收集的对象类型(想想 IDisposable 和朋友)

您想要实现的是,在您的大对象超出范围后,它使用的内存尽可能快地转到 (D)。这里有一些提示:

  • 确保您的对象的大小是 4K 的倍数 - 这使得没有其他对象与您的对象共享内存页面的可能性更大,因此可以更轻松地将其返回给操作系统

  • 尝试AddMemoryPressure()在对象处理周围使用支架,但要注意副作用。这类似于强制GC.Collect(),但侵入性较小:它会提示 GC很快收集,但不完全是现在

  • 重新思考你的基本概念:大对象是单例吗(即在任何给定时间只能存在一个)?如果是,请考虑分配一次并回收它:这将使您的应用程序 RAM 需求更可预测 - 并且可能使您在运行时避免丑陋的 OOM 情况。

于 2012-07-06T09:22:59.703 回答
0

使用 IDisposable 意味着您正在实现 Dispose 方法,在该方法中,您将所有清理代码用于不再需要的资源。它不会将您的对象移至托管堆,GC 仍将负责释放内存。

于 2012-07-06T09:51:39.793 回答
-2

当您实现 IDisposable 并释放该对象时,您就是将该对象标记为可用于垃圾回收。

但是,您无法准确预测何时收集它。

于 2012-07-06T09:15:42.497 回答