我在一个运行SQL脚本并将结果转储到文件的服务程序中遇到了内存泄漏问题。运行产生大量结果行的查询后,进程的内存使用量每次增加50+ MB,并且不会下降。
以下是打开连接并检索结果的代码:
第二列是对象数量,第三列是总大小。
不应该有任何未处理的System.Data.DataRow对象。看起来它们被泄漏了,但我不确定原因在哪里。
我做错了什么?
注意:之前的版本使用SqlDataReader检索行数据,但这种方法缺乏获取列标题的方式(据我所知),并且在DataSet和SqlDatReader之间共享数据集会在某些查询上静默失败。我不记得那个版本有内存泄漏问题。
以下是打开连接并检索结果的代码:
using (var conn = new SqlConnection(DataSourceInfo.ConnectionString))
{
conn.Open();
var scmd = new SqlCommand(query_string, conn);
scmd.CommandTimeout = 86400;
var writer = dest.GetStream(); //the writer is disposed of elsewhere
using (var da = new SqlDataAdapter(scmd))
using (var ds = new DataSet())
{
da.Fill(ds);
var table = ds.Tables[0];
var rows = table.Rows;
if (TaskInfo.IncludeColNames.Value)
{
object[] cols = new object[table.Columns.Count];
for(int i = 0; i < table.Columns.Count; i++)
cols[i] = table.Columns[i];
LineFormatter(writer, TaskInfo.FieldDelimiter, null, false, cols);
writer.WriteLine();
}
foreach(System.Data.DataRow r in rows)
{
var fields = r.ItemArray;
LineFormatter(writer, TaskInfo.FieldDelimiter, TaskInfo.TextQualifier, TaskInfo.TrimFields.Value, fields);
writer.WriteLine();
}
}
}
我使用WinDbg和sos.dll,在执行完成后,进程有足够的时间进行GC,列出了按类型排名前几的对象:
79333470 101 166476 System.Byte[]
65245dcc 177 3897420 System.Data.RBTree`1+Node[[System.Data.DataRow, System.Data]][]
0015e680 5560 3968936 Free
79332b9c 342 3997304 System.Int32[]
6524508c 120349 7702336 System.Data.DataRow
793041d0 984 22171736 System.Object[]
7993bec4 70 63341660 System.Decimal[]
79330a00 2203630 74522604 System.String
第二列是对象数量,第三列是总大小。
不应该有任何未处理的System.Data.DataRow对象。看起来它们被泄漏了,但我不确定原因在哪里。
我做错了什么?
注意:之前的版本使用SqlDataReader检索行数据,但这种方法缺乏获取列标题的方式(据我所知),并且在DataSet和SqlDatReader之间共享数据集会在某些查询上静默失败。我不记得那个版本有内存泄漏问题。
SqlCommand
包装在using
语句中吗? - kbrimington