1

好吧,我试图了解可以通过代码显式完成的内存过程的释放。

我在下面的 MS 线程中看到 Dispose 方法是在 Component 类中实现的。在这里,我有三个疑问。

  1. 组件类派生自 IDisposable,但是,在这个类库中,我发现它没有实现方法 Dispose,甚至看起来都不是“public void Dispose() {}”。但是当我只是编写一个类并声明一个没有任何主体的方法时,它会给我编译时错误说,我应该定义主体或使其抽象。为什么会有这种差异?

  2. 我一般用这种方式,比如说“connection.Dispose();” 在 finally 块中处理 sqlconnection。我知道,SqlConnection 是从 DBConnection 派生的,而 DBConnection 又是从 Component 派生的。当我查看 Component 类时,我只看到方法“public void Dispose();”的声明 那么它实际上是在哪里实现的呢?

  3. 我还看到了一些专门实现的代码,例如下面 MS 网站中给出的代码。他们为 Dispose 状态声明了一个 bool 变量,并有一个新的 Dispose 方法,他们在该方法中调用对象上的 Component Dispose。他们还对非托管资源使用 Kernel32 方法 CloseHandle。这种方法有什么用?在处理它时,我从未将它用于我的 SqlConnection (这也是一个非托管资源)。

http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize(v=vs.110).aspx

有人也可以帮助我简短地理解上面的三个问题。我只是在学习所有这些。谢谢

4

2 回答 2

3

首先:

public void Dispose() { }

一个身体——它只是一个空的。这里没有区别。实际上,虽然Component.Dispose是:

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

如果你想添加逻辑,这个想法是你override的方法。protected virtual void Dispose(bool disposing)

其次,如果你这样打电话connection.Dispose(),那么你做错了。你应该使用一个using块:

using(var conn = ...)
{
    conn.Open();
    using(var cmd = conn.CreateCommand())
    {
        // etc etc
    }
    // look ma, no finally
}

您的第三点以及您引用的 MSDN 文章只是您可能实际需要执行此操作的一个示例。该CloseHandle方法只是非托管资源的一个说明。这是关键,因为您不使用终结器来清理托管资源 - 只有 unmaged。因此,一个涉及非托管句柄的示例是一个简单的借口来说明:

  • Dispose(false)从终结器调用
  • overrideDispose(bool)方法_
  • Dispose(false)有一些代码(句柄)从终结器和处置(分别和Dispose(true))中得到清理
  • 有一些只为Dispose(true)案例执行的代码 - 即继续处理
于 2013-11-10T20:33:22.693 回答
1

首先要明确的是 Dispose()与内存完全无关IDisposable 模式完全是关于清理非托管资源......也就是说,清理除了内存之外的任何东西。

Component.Dispose()记录在这里:

http://msdn.microsoft.com/en-us/library/3cc9y48w.aspx

请注意以下事项,除了:

调用 Dispose 后,您必须释放对 Component 的所有引用,以便垃圾收集器可以回收 Component 占用的内存。

同样,我们看到 Dispose()-ing 对象是与释放内存不同的问题。

在 的情况下SqlConnection,有一个继承层次结构在起作用。类型本身有一个空Dispose()方法Component(空方法是合法的)。该方法是空的,因为基类本身没有任何需要担心的非托管资源。该SqlConnection类型覆盖了基本实现,因此它将关闭与服务器的连接。

现在让我们谈谈终结器。终结器也与内存无关,只是它们由垃圾收集器调用。终结器的目的是在收集对象时释放非托管(非内存)资源。如果您正在构建一个使用大量非托管资源的类,这样就不会有争用或耗尽资源的风险,那么终结器本身就足够了,而 Dispose() 没有任何用处。然而,几乎所有的计算资源都有一定程度的稀缺性,因此您可能不想在释放它们之前等待垃圾收集器。垃圾收集器可能在一段时间内不会收集对象,因此 Dispose() 模式的存在是为了提供一种及时、可预测的方式释放非托管资源的方法。

商品消息是,大多数时候,您无需担心终结器。如果你正在构建一种全新的非托管资源,你只需要实现一个终结器。例如,如果程序中有一个类型通过包装 SqlConnection 类来管理与 Sql Server 数据库的连接,则不需要终结器。这可能是一个新类,但 SqlConnection 类型最终处理释放您的数据库连接。但是,您应该在您的类型中实现或使用 IDisposable,以便它管理的连接将被及时释放。另一方面,如果您正在构建一种全新的数据库引擎来与 Sql Server 竞争,或者要从头开始重新实现 Sql Server 连接协议,那么您将需要一个终结器。

有时,您的 Dispose() 方法需要禁止完成。例如,如果在释放非托管资源后再次尝试释放非托管资源会导致不必要的异常,则您可能会这样做。

我想我已经涵盖了您三个问题的大部分要点,但仍有一些问题需要解决:

它看起来是“public void Dispose() { }”。但是当我只写一个类并声明一个没有任何主体的方法时,它给我编译时错误说,我应该定义主体

该方法有一个主体。{ } 方法的主体。只是它是空的。

[SqlConnection.Dispose()] 实际在哪里实现?

您正在查看 IDE。这仅显示方法声明和基本描述。那里有更多的代码。如果您真的想要它,可以使用完整的 .Net 源代码

他们还对非托管资源使用 Kernel32 方法 CloseHandle。这种方法有什么用?

这只是一种特定于处理特定类型资源的方法。IDisposable 模式的部分目的是提供一个标准的地方来放置这种东西,这样你作为程序员就不需要知道这些东西来正确地处理一个对象。

于 2013-11-10T20:34:54.560 回答