是否会通过GC处理SqlConnection?

Nel*_*mel 13 .net idisposable sqlconnection finalizer

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

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

Jon*_*nna 9

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

有一个终结者System.ComponentModel.Component,但它被压制成了SQLConnection构造函数.这是一个好主意,如果你继承了你知道100%确定你不会需要的终结者的东西,否则就是一个坏主意.在这种情况下,这是一个好主意.

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

现在,请记住,只有那些直接持有非托管资源的对象或者其他非GC关注的对象才需要最终确定.SqlConnection拥有一个对象,可以(取决于状态SqlConnection)是一个拥有非托管资源的对象(或者实际上,通过类的嵌套更深).因此,没有必要SqlConnection最终确定.考虑一个开放SqlConnection可以停止开放的三种可能方式SqlConnection:

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

现在,在第三种情况下,该对象保存对具有真实连接的对象的引用.它也是唯一这样做的对象.因此,该对象也将被垃圾收集.如果它有一个终结者(它可能会有,但我不会假设没有进一步的巧妙技巧),那么终结者将把它放到终结者队列中,并最终确定.

如果SqlConnection有一个终结者,唯一真正的影响将是:

  1. 有缺陷代码的可能性(在终结器代码中处理可终结成员是充满希望的,因为您不知道他们是否已经完成).
  2. 放慢速度的可能性(无论如何,真正的连接将最终确定,充其量我们只是放慢了最终化和GC).
  3. 无论如何这里没什么可做的(真正的连接将在没有任何帮助的情况下完成).

因此,在SqlConnection没有获胜的情况下,将终结者放在上面是一种失败.此外,您的真实连接有望最终完成.

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

你是否需要为一个IDataReader或一个IDataReader允许完成的对象保持活着?在这种情况下,你可以使用CommandBehavior.CloseConnection标志,以便关闭(或处置)阅读器关闭连接?后一种情况是唯一一种我可以回想起不得不让连接离开范围的情况.