14

免责声明:我知道IDisposable在处理非托管资源时应该实施。其余的代码应该是确定性的并且做using (...) { }(相当于try {} finally { Dispose(); })以保证尽快清理。此外,GC不会调用Dispose(),因此推荐的模式是覆盖Finalize()然后调用Dispose(). GC 通常会调用Finalize()(除非GC.SuppressFinalize()已调用)。

问题:using (SqlConnection...) { }所以现在我解决了这个问题,我遇到了一个奇怪的情况,由于代码超出我的控制,我无法做到这一点。我通常可以做一个确定性的Dispose(),但不能保证。我使用 Reflector 进行反汇编SqlConnection,发现它使用了 Dispose(),但除非我是盲人,否则没有终结器/析构函数(Finalize()~SqlConnection())。这是否意味着在我不能的奇怪情况下,GC 不会“清理”(发送回池)连接?我一直找不到任何确定的...

4

1 回答 1

11

好吧,它不会被处置,因为最终确定不是处置。

中有一个终结器System.ComponentModel.Component,但在SQLConnection的构造函数中被抑制了。如果您从具有终结器的东西继承,这是一个好主意,您知道 100% 确定您不需要,但否则是个坏主意。在这种情况下,这是个好主意。

但请记住,这SqlConnection是对“真实”连接的包装。实际上,它很可能是一组变化的对象的包装,这些对象代表不同的连接状态。这是允许“真实”连接有效池化的机制的一部分,因为每次调用Open()它都会从池中获取相关对象,并且每次调用时Close()(无论是直接调用,Dispose()还是通过离开一个范围using) 它返回它。

现在,请记住,只有直接持有非托管资源或其他与 GC 无关的对象才需要最终确定。SqlConnection持有一个对象,该对象可能(取决于 的状态SqlConnection)是持有非托管资源的对象(或者实际上,更深于类的嵌套)。因此,没有必要对SqlConnectionto 本身进行最终确定。SqlConnection考虑 open不再是 open的三种可能方式SqlConnection

  1. Close()叫做。这会立即返回到池的真实连接(如果没有池,则将其关闭)。
  2. Dispose()叫做。这调用Close()具有相同的效果。
  3. 该对象被垃圾收集。

现在,在第三种情况下,对象持有对具有实际连接的对象的引用。它也是唯一这样做的对象。因此,该对象也将被垃圾收集。如果它有一个终结器(它可能有,尽管我不会假设没有更多聪明的技巧在进行),那么终结器将导致它被放入终结器队列中,并且最终会被终结。

如果SqlConnection有一个终结器,唯一真正的效果是:

  1. 潜在的错误代码(在终结器代码中处理可终结的成员是令人担忧的,因为你不知道它们是否已经被终结)。
  2. 可能会减慢速度(无论如何,真正的连接都会被最终确定,充其量我们只是在减慢最终确定和 GC 的速度)。
  3. 无论如何,这里无事可做(真正的连接将在没有任何帮助的情况下完成)。

因此,将决赛选手放在比赛中SqlConnection是没有胜利的失败。此外,您的真正联系应该有望最终确定。

这就是说,它仍然远非理想,并且仍然可能泄漏连接。你能详细说明为什么你不能打电话Close()或处置自己吗?管理连接的代码不能为您调用 close(对象应该在某个地方结束它的日子,并且应该在那里关闭)吗?

您是否需要让它保持活动状态才能允许IDataReader从 an 提供的对象或对象完成?IDataReader在这种情况下,您可以使用该CommandBehavior.CloseConnection标志以便关闭(或处置)阅读器关闭连接吗?后一种情况是我记得的唯一一种不得不让连接离开作用域的情况。

于 2010-09-03T16:42:28.493 回答