首页 > 解决方案 > c# 中的简单批处理文件处理函数中可能存在内存泄漏

问题描述

我正在运行一个非常简单的函数,它从文本文件中批量读取行。每行包含一个 sql 查询,因此该函数获取指定数量的查询,针对 SQL 数据库执行它们,然后获取下一批查询,直到读取整个文件。问题是随着时间的推移,文件非常大,该过程开始显着减慢。我猜函数中某处存在内存泄漏,但无法确定它可能在哪里。此功能运行时没有其他任何事情发生。我的编程技能充其量是粗略的,所以请放轻松。:)

    for (int x = 0; x<= totalBatchesInt; x++)
    {
    var lines = System.IO.File.ReadLines(file).Skip(skipCount).Take(batchSize).ToArray();
    string test = string.Join("\n", lines);
    SqlCommand cmd = new SqlCommand(test.ToString());
        try
        {
            var rowsEffected = qm.ExecuteNonQuery(CommandType.Text, cmd.CommandText, 6000, true);
            totalRowsEffected = totalRowsEffected + rowsEffected;
            globalRecordCounter = globalRecordCounter + rowsEffected;
            fileRecordCounter = fileRecordCounter + rowsEffected;
            skipCount = skipCount + batchSize;
            TraceSource.TraceEvent(TraceEventType.Information, (int)ProcessEvents.Starting, "Rows 
            progress for " + folderName + "_" + fileName + " : " + fileRecordCounter.ToString() + " 
            of " + linesCount + " records");
        }
        catch (Exception esql)
        {           
            TraceSource.TraceEvent(TraceEventType.Information, (int)ProcessEvents.Cancelling, "Error 
            processing file " + folderName + "_" + fileName + " : " + esql.Message.ToString() + ". 
            Aborting file read");       
        }
    }

标签: c#sqlmemory-managementmemory-leaks

解决方案


您的代码有很多问题:

  1. 你永远不会处置你的命令。这是 ODBC 驱动程序的本机句柄,等待垃圾收集器处理它是非常糟糕的做法。

  2. 无论如何,您不应该单独发送这些命令。要么在一个命令中一次性发送它们,要么使用事务将它们组合在一起。

  3. 这就是它随着时间变慢的原因:File.ReadLines(file).Skip(skipCount).Take(batchSize)将一遍又一遍地读取同一个文件并忽略每次尝试越来越多的行,因此随着被忽略(但已处理)的行数越来越大而越来越慢.

要修复 #3,只需创建一次枚举器并分批迭代它。在纯 C# 中,您可以执行以下操作:

using var enumerator = File.ReadLines(file).GetEnumerator();

for (int x = 0; x<= totalBatchesInt; x++)
{
    var lines = new List<string>();
    while(enumerator.MoveNext() && lines.Count < batchSize)
        list.Add(enumerator.Current);
    string test = string.Join("\n", lines);
    // your code...
}

或者,如果您使用的是 Morelinq(我推荐),则如下所示:

foreach(var lines in File.ReadLines(file).Batch(batchSize))
{
    // your code...
}

推荐阅读