使用StreamReader进行内存泄漏(?)

时间:2012-10-02 11:16:48

标签: c# streamreader

我有一些非常大的文件,每个500MB++大小,包含整数值(实际上它有点复杂),我正在循环中读取这些文件并计算所有文件的最大值。由于某种原因,内存在处理过程中不断增长,看起来GC似乎永远不会释放由lines之前的实例获取的内存。

我无法流式传输数据,必须为每个文件使用GetFileLines。如果为一个文件存储lines所需的实际内存量为500MB,为什么在处理10个文件后会使用5GB RAM int max = int.MinValue; for (int i = 0; i < 10; i++) { IEnumerable<string> lines = Db.GetFileLines(i); max = Math.Max(max, lines.Max(t=>int.Parse(t))); } ?最终,在15个文件后,它会因内存不足而崩溃。

计算:

   public static List<string> GetFileLines(int i)
   {
      string path = GetPath(i);

      //
      List<string> lines = new List<string>();
      string line;

      using (StreamReader reader = File.OpenText(path))
      {
         while ((line = reader.ReadLine()) != null)
         {
            lines.Add(line);
         }

         reader.Close();
         reader.Dispose(); // should I bother?
      }

      return lines;
   }

GetFileLines代码:

{{1}}

6 个答案:

答案 0 :(得分:5)

对于非常大的文件,方法ReadLines最适合,因为它是延迟执行,它不会在内存中加载所有行并且易于使用:

  Math.Max(max, File.ReadLines(path).Max(line => int.Parse(line)));

更多信息:

http://msdn.microsoft.com/en-us/library/dd383503.aspx

修改

这就是ReadLines在幕后实现的方式:

    public static IEnumerable<string> ReadLines(string fileName)
    {
        string line;
        using (var reader = File.OpenText(fileName))
        {
            while ((line = reader.ReadLine()) != null)
                yield return line;
        }
    }

此外,当您有多个文件时,建议使用并行处理来提高性能

答案 1 :(得分:4)

您可能会崩溃,因为在完成处理后,您将在内存中保留对已解析结果的引用(您显示的代码不会执行此操作,但是您运行的代码是否相同?)。 StreamReader中存在这样的错误的可能性极小。

您确定必须立即读取内存中的所有文件吗?可能使用可枚举的行序列IEnumerable<string>而不是在前面加载List<string>。至少在这段代码中没有任何东西禁止这样做。

最后,CloseDispose来电是多余的; using会自动处理此问题。

答案 2 :(得分:1)

为什么不实现如下:

int max = Int32.MinValue;
using(var reader = File.OpenText(path)) 
{
    while ((line = reader.ReadLine()) != null)
    {
         int current;
         if (Int32.TryParse(line, out current))
             max = Math.Max(max, current);
     }    
}

答案 3 :(得分:0)

您正在将整个文件读入内存(列表行)

我猜你一次只能读一行并保持最高数字?

它会为你节省很多内存。

答案 4 :(得分:0)

您似乎总是将整个文件加载到内存中。同时,您还要为文件的每一行创建托管对象(List)。

没有理由让你的内存使用量增长。

请发布其余的代码,我怀疑你是在某个地方参考这个正在使用的列表,因此它没有被处置。

答案 5 :(得分:0)

好吧,如果你想要一个可以一次阅读整个文件的解决方案,因为你肯定你需要获得性能提升,那么让我们这样做,这样就可以了没有记忆问题。

public static int GetMaxForFile(int i) 
{ 
    string path = GetPath(i); 

    var lines = new List<string>(File.ReadAllLines(path));

    // you MUST perform all of your processing here ... you have to let go
    // of the List<string> variable ...
    int max = Math.Max(max, lines.Max(t=>int.Parse(t)));

    // this may be redundant, but it will cause GC to clean up immediately
    lines.Clear();
    lines = null;

    return max;
}