5

それぞれの500MB++サイズが整数値を含む非常に大きなファイルがいくつかあります (実際にはもう少し複雑です)。これらのファイルをループで読み取り、すべてのファイルの最大値を計算しています。なんらかの理由で、処理中にメモリが絶えず増加しています。GC は、 の以前のインスタンスによって取得されたメモリを決して解放しないようですlines

データをストリーミングできず、GetFileLinesファイルごとに使用する必要があります。lines1 つのファイルを格納するのに必要な実際のメモリ量が であるとすると、 10 個のファイルを処理した後に慣れてしまうのは500MBなぜですか? 最終的に、15 個のファイルの後、メモリ不足の例外でクラッシュします。5GBRAM

計算:

   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>。少なくともこのコードでは、これを禁止するものは何もありません。

最後に、CloseandのDispose呼び出しは冗長です。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

ファイル全体をメモリに読み込んでいます(リスト行)

一度に1行ずつ読んで、最大数を維持できると思いますか?

それはあなたにたくさんのRAMを節約します。

于 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 に答える