.NET 4.0下SQL句柄泄漏问题,但在.NET 3.5下不存在。

3

以下示例代码会导致句柄泄漏。句柄计数从133开始,在不到2小时内就达到了900。示例使用的是VS2010和.Net 4.0。这在.Net 3.5上不会发生。 我已经在超过3台机器上复现了这个问题,都是Win2008 R2服务器,包括SQL 2008和SQL 2012。这些机器都是虚拟机,并且每周回滚两次,因此非常干净。

//Reference dll are the ones required for SQL 
//.Net 4.0 (not 'Client Profile' version)
static void Main(string[] args)
{

    string sss = "Data Source=WIN-0BDHQ0IIUFL,1433;Initial Catalog=DB_Mycentral;Persist Security Info=False;User ID=Myuser;Password=123;Connect Timeout=60;Network Library=dbmssocn";
    System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(sss);
    int i = 0;
    while (true)
    {
        i++;

        Thread.Sleep(1000 * 60 * 60);
        Console.WriteLine("{0} hrs sleep", i);
    }
}

我观察了ProcMon.exe中的活动并查看了ProcExp.exe中的调用堆栈。ProcMon.exe反复记录了CreateThread()和ExitThread()。然后,ProcExp.exe显示cld.dll!StrongNameErrorInfo+0x18910与新创建的TID相关联。最后,在ProcExp.exe中,THREAD对象计数增加了一个。整个过程不断重复。

Example for leaking of TID 9089:
CreateThread()/ExitThread() TID:9089 //Log in ProcMon.exe
cld.dll!StrongNameErrorInfo+0x18910  TID: 9089  //Call-stack in ProcExp.exe

背景:我写了这个示例来缩小我们生产代码中的泄漏范围。该代码在 .Net 3.5 中运行良好,但在 .Net 4.0 中泄漏。
请告诉我是否需要在打开连接时设置额外的标志。

2
你正在依赖终结器(因为你没有处理),所以除非垃圾回收器运行,否则你将无法得到终结。http://dotnettips.wordpress.com/2011/10/24/net-4-0-bug-with-sqlconnection-object/ - Darren Kopp
考虑到编写问题所花费的时间,使用谷歌搜索SqlConnection Leak Handle可能会更好...它似乎很出名。这表明当你遇到问题时,首先要用谷歌搜索。 - xanatos
谢谢Kopp。我会尝试微软建议的解决方案。 - user1174790
代码只会打开一个连接,不应该泄漏。之前的评论不适用。 - usr
Usr2:是的,它只打开连接但仍然泄漏。在几台机器上验证过了。 - user1174790
1个回答

0
使用 'using' 来确保 dispose 方法总是被调用。
请参阅 http://msdn.microsoft.com/en-us/library/yh598w02.aspx
//Reference dll are the ones required for SQL 
//.Net 4.0 (not 'Client Profile' version)
static void Main(string[] args)
{

    string sss = "Data Source=WIN-0BDHQ0IIUFL,1433;Initial Catalog=DB_Mycentral;Persist Security Info=False;User ID=Myuser;Password=123;Connect Timeout=60;Network Library=dbmssocn";
    using(System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(sss))
    {

        int i = 0;
        while (true)
        {
            i++;

            Thread.Sleep(1000 * 60 * 60);
            Console.WriteLine("{0} hrs sleep", i);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接