使用SqlConnection时,务必在使用时关闭它 - 通过.Close()或将SqlConnection置于“using”中。幸运的是,包括我在内的人往往忘记这一点,这就是垃圾收集者拯救我一段时间的地方,直到我忘记关闭我的连接太多次或者使用该应用程序的人数增加。
我想知道,如果可能的话,如何检测垃圾收集器是否处置了SqlConnection,因为它认为它已经不再使用,或者SqlConnection是否以正确的方式关闭。
另一种方法可能是继承SqlConnection并在其初始化程序上放置一个计时器,并检查在处理该类时关闭连接所需的时间。我真的不喜欢计时器,但这个想法只是在写这篇文章的时候出现了。
也许还有第三种甚至是更聪明的方式......你会推荐什么?
答案 0 :(得分:4)
由于SqlConnection已密封,您将无法继承它。 (我不认为这样做是个好主意 - 如果有可能,你应该在Dispose(false)中添加你的代码,因为这是终结器调用的。)
最好通过使用静态代码分析工具来检测这类问题,该工具可以检测代码中忘记处理连接的所有位置。内置in Visual Studio,或者您可以使用FxCop。
为了帮助您不要忘记处理连接,最好:
答案 1 :(得分:2)
一条经验法则说:“如果你不得不考虑垃圾收集器,你可能会做错事。” (当然,还有其他的拇指......)
在我看来,确保明确地或通过using
和finally
块关闭连接是最佳途径。
显然,你已经理解了这些技术......所以也许你只需要一次通过代码和可能的重构。
答案 2 :(得分:1)
如果您的应用程序使用SQL连接池(默认),则无关紧要,因为连接被重新使用,并且在您调用.Close()或保留using(){}块时不会关闭。
http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx
为了回答你的问题,我不相信GC收集有一个事件,但是如果有的话也没关系,因为你永远不会知道GC是否选择在该收集通道上回收你的对象(并非所有对象都是由于代际算法而被清理。
我也会避免尝试使用计时器和“检查”,因为您可能会保留对该对象的引用并防止它被丢弃。
答案 3 :(得分:1)
我对垃圾收集器不太熟悉,不知道是否有直接获取信息的方法,但我的第一个想法是下面的。
只需为虚拟对象创建weak reference即可。如果您稍后查看弱引用并且对象不再是alive,您可能会认为发生了垃圾收集。
(这个答案仅适用于检测垃圾收集器运行。我完全忽略了这样做的原因 - 有更好的策略来处理资源泄漏。)
答案 4 :(得分:0)
如果您忘记处置,该对象将被最终确定。无法控制发生这种情况的时间,也无法知道对象是否已完成。必须创建一个单独的线程才能完成对象,因此会降低应用程序的速度。这就是你想要处理的原因。在框架中实现IDisposable的所有类中,都会调用GC.SuppressFinalize,因此该对象尚未最终确定。
您无法控制此行为。如果您的对象不再使用,将自动收集。所有你能做到的就是停止这个,叫做GC.SuppressFinalize,但我不建议这样做,因为如果你忘记了,你就会被终身搞砸。
您可以创建一个包装类(不是子类),您在代码中使用它提供一些总是调用Dispose的简单方法。否则,请检查一下。
答案 5 :(得分:0)
首先,如果你甚至考虑使用GC,你在某个地方遇到了严重的问题。我建议确保代码调用Close的最佳方法是使用mocking等技术对代码进行单元测试。如果您的单元测试表明已调用Close,那么您的代码是正确的,并且您不必做任何不必要的危险,例如乱扔垃圾收集器。
其次,如果您仍坚持使用运行时检查路由,那么您应该考虑的仅事情是挂钩SqlConnection
{{1}}事件。例如,如果ConnectionState从Open变为Closed,那将会触发。