5

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

我无法流式传输数据并且必须GetFileLines为每个文件使用。lines假设存储一个文件所需的实际内存量是500MB,为什么在处理 10 个文件后我就用完了5GBRAM最终它在 15 个文件后因内存不足异常而崩溃。

计算:

   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)));
   }

GetFileLines 代码:

   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;
   }
4

6 回答 6

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;
        }
    }

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

于 2012-10-02T11:23:46.927 回答
4

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

您确定必须一次读取内存中的所有文件吗?很有可能使用可枚举的行序列IEnumerable<string>而不是预先加载List<string>。至少在这段代码中没有什么禁止这样做的。

最后,CloseandDispose调用是多余的;using自动处理。

于 2012-10-02T11:21:03.667 回答
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);
     }    
}
于 2012-10-02T11:22:53.150 回答
0

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

我想你可以一次读一行并保持最高的数字吗?

它会为你节省很多内存。

于 2012-10-02T11:21:23.410 回答
0

您似乎总是在内存中加载整个文件。同时,您也在为文件的每一行创建托管对象(列表)。

您的内存使用量没有理由增加。

还请发布其余代码,我怀疑您是否在某个地方引用了正在使用的此列表,因此它没有被处理。

于 2012-10-02T11:24:44.877 回答
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;
} 
于 2012-10-02T11:26:54.467 回答