免责声明:我知道在处理非托管资源时应该实现IDisposable
。其余代码应该是确定性的,并using (...) { }
(相当于try {} finally { Dispose(); }
)以确保尽快清理。此外,GC将not call Dispose()
,因此推荐的模式是覆盖Finalize()
方法(使用析构函数语法在C#中),然后调用Dispose()
。 GC通常会调用Finalize()
(除非已调用GC.SuppressFinalize()
)。
问题:所以现在我已经解决了这个问题,我有一个奇怪的情况,由于代码无法控制,我无法using (SqlConnection...) { }
。我通常可以做一个确定性的Dispose()
,但不能保证。我使用Reflector来反汇编SqlConnection
并看到它使用Dispose(),但除非我是盲目的,否则没有终结器/析构函数(Finalize()
或~SqlConnection()
)。这是否意味着GC不会“清理”(发送回池)连接在奇怪的情况下我不能?我找不到任何确定的东西......
答案 0 :(得分:8)
好吧,它不会被处理掉,因为最终决定不会被处置。
System.ComponentModel.Component
中有一个终结者,但它在SQLConnection
的构造函数中被压制。这是一个好主意,如果你继承了你知道100%确定你不会需要的终结者的东西,否则就是一个坏主意。在这种情况下,这是一个好主意。
请记住,SqlConnection
是“真实”连接的包装器。实际上,它很可能是表示不同连接状态的不断变化的对象集的包装器。这是允许有效汇集“真实”连接的机制的一部分,因为每次调用Open()
时,它都会从池中获取相关对象,并且每次调用Close()
时(无论是否)直接地,通过Dispose()
或通过留下using
的范围,它将返回它。
现在,请记住,只有那些直接持有非托管资源的对象或其他不是GC关注的对象才需要最终确定。 SqlConnection
拥有一个对象,该对象可能(取决于SqlConnection
的状态)是一个拥有非托管资源的对象(或者实际上,通过类的嵌套更深)。因此,SqlConnection
本身无需最终确定。考虑开放SqlConnection
可以停止成为开放SqlConnection
的三种可能方式:
Close()
被调用。这会立即返回到池的实际连接(如果没有池,则关闭它)。Dispose()
被调用。这会调用Close()
具有相同的效果。现在,在第三种情况下,该对象保存对具有真实连接的对象的引用。它也是唯一这样做的对象。因此,该对象也将被垃圾收集。如果它有一个终结者(它可能会有,但我不会假设没有进一步的巧妙技巧),那么终结者将使它被放入终结者队列,并最终完成。
如果SqlConnection
有终结者,唯一真正的影响是:
所以,在SqlConnection
上放置终结者是一场没有胜利的输球。此外,您的真实连接有望最终确定。
这就是说,它仍然远非理想,仍然非常可能泄漏连接。你能详细说明为什么你不能打电话给Close()
或处理你自己?管理连接的代码是否可以为您调用(对象应该结束某处,并且应该在那里关闭)?
您是否需要为IDataReader
或从IDataReader
供稿的对象保持活动状态?在这种情况下,您是否可以使用CommandBehavior.CloseConnection
标志,以便关闭(或处置)阅读器关闭连接?后一种情况是唯一一种我可以回想起曾经不得不让一个连接留下范围的情况。