连接泄漏 (C#/ADO.NET) 即使 SqlConnection 使用 using 创建



我有一个程序,它在线程池上运行的任务中加载大量数据(每次迭代~800K-1M行((请参阅下面的违规代码示例(;同时运行的任务不超过4个。这是程序中唯一与此数据库建立连接的地方。在我的笔记本电脑(和其他同事相同的笔记本电脑(上运行该程序时,该程序运行良好。但是,我们可以通过远程桌面访问另一个工作站,该工作站的功能比我们的笔记本电脑强大得多。该程序在其列表中失败了大约 1/3 到 1/2。所有任务都返回异常。

第一个例外是:"超时已过期。 从池获取连接之前经过的超时期限。 这可能是因为所有池连接都在使用中,并且已达到最大池大小。我尝试过谷歌搜索,狂欢,搜索StackOverflow,并用头撞桌子,试图弄清楚这是怎么回事。如果同时运行的任务不超过 4 个,则每次的连接不应超过 4 个。

针对这一点,我尝试了两件事:(1(我在conn周围添加了一个尝试/捕获。Open(( 行,如果出现 InvalidOperationException,它将清除池 - 这似乎有效[没有让它一直运行,但基本上超过了以前的位置],但以性能为代价。(2(我将ConnectionTimeout更改为30秒而不是15秒,这不起作用(但让它再继续一点(。我还尝试过执行 ConnectRetryInterval=4(错误地选择了这个而不是 ConnectRetryCount(——这导致了不同的错误"最大请求数为 4,800",这很奇怪,因为我们仍然不应该接近 4,800 个请求或连接。

简而言之,我不知所措,因为我无法弄清楚仅在高速计算机上导致此连接泄漏的原因。我也无法让该计算机上的Visual Studio直接调试 - 任何人可能对在哪里尝试解决此问题的任何想法将不胜感激。

(跟进 c# 任务工厂继续在所有任务完成之前意外运行(

private void LoadData()
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = "redacted";
builder.UserID = "redacted";
builder.Password = "redacted";
builder.InitialCatalog = "redacted";
builder.ConnectTimeout = 30;
using (SqlConnection conn = new SqlConnection(builder.ConnectionString))
{
//try
//{
//    conn.Open();
//} catch (InvalidOperationException)
//{
//    SqlConnection.ClearPool(conn);
//    conn.Open();
//}
conn.Open();

string monthnum = _monthsdict.First((x) => x.Month == _month).MonthNum;
string yearnum = _monthsdict.First((x) => x.Month == _month).YearNum;
string nextmonthnum = _monthsdict[Array.IndexOf(_monthsdict, _monthsdict.First((x) => x.Month == _month))+1].MonthNum;
string nextyearnum = _monthsdict[Array.IndexOf(_monthsdict, _monthsdict.First((x) => x.Month == _month)) + 1].YearNum;
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = @"redacted";
cmd.Parameters.AddWithValue("@redacted", redacted);
cmd.Parameters.AddWithValue("@redacted", redacted);
cmd.Parameters.AddWithValue("@redacted", redacted);
cmd.CommandTimeout = 180;
SqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
Data data = new Data();
int col1 = reader.GetOrdinal("col1");
int col2 = reader.GetOrdinal("col2");
int col3 = reader.GetOrdinal("col3");
int col4 = reader.GetOrdinal("col4");
data.redacted = redacted;
data.redacted = redacted;
data.redacted = redacted;
data.redacted = redacted;
data.redacted = redacted;
data.Calculate();
_data.Add(data); //not a mistake, referring to another class variable
}
reader.Close();
cmd.Dispose();
conn.Close();
conn.Dispose();
}
}

事实证明,这是一个没有足够仔细地阅读文档的经典案例。我试图使用 ThreadPool.SetMaxThreads 将最大线程数限制为 4,但最大线程数不能小于处理器数。在它失败的工作站上,它有 8 个处理器。因此,从来没有上限,它运行的任务数量与任务计划程序认为合适的任务一样多,最终达到了连接池限制。

https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadpool.setmaxthreads

相关内容

最新更新