3

したがって、MemoryStream を使用して StreamWriter とこのアプリケーションの内部に書き込む StreamReader を使用していますが、メモリ使用量が (より大きな入力の 1 つから) 300mb 増加し、使用が終わった後に割り当てを解除しません:

StreamWriter log = new StreamWriter("tempFile.txt");
log.Write(reader.ReadToEnd());
log.Close();

reader.DiscardBufferedData();
reader.Close();
reader.Dispose();
memoryStream.Dispose();
log.Dispose();
GC.Collect();

これの前と RAM 使用量を取得した直後で、前は後よりも 300 MB 少なくなっていますが、その理由はわかりません。ここで起こっているのは、リーダーからのデータがテキストファイルに配置されていることだけであることを考慮して、そのメモリを解放するために考えられるすべてのことを行いました。なぜ大量のメモリを使用する必要があるのか​​ わかりません一時的に。不足しているものはありますか?...ありがとう。

4

4 に答える 4

6

プロセス自体が使用する RAM を見ていますか? それが下がるとは思わなかった。プロセスはそのメモリを保持し、その後の割り当てに再利用します。オペレーティング システムには返されません。これが、.NET が機能する傾向にある方法です。

いくつかの CLR API 呼び出しでメモリを破棄する可能性がありますが、通常はそうしません。

これは、メモリが実際にリークしたという意味ではありません。同じプロセスでまだ使用できます。たとえば、同じアクションを再度実行した場合、おそらくヒープのサイズを増やす必要はありません。メモリ使用量はプロセス レベルで横ばいであることがわかります。CLR perfmon グラフを使用して、マネージ ヒープ内で使用されているメモリを確認し、本物のリークがあるかどうかを確認します。

(アプリケーションが実際に使用しているメモリの量についても、さまざまな尺度があります。どれが興味深いかは、何をしようとしているかによって異なります。)

編集: コード スニペットが使用しているコードを真に示している場合は、はるかに簡単な代替手段があります: データをストリーミングします。

using (TextWriter writer = File.CreateText("tempFile.txt"))
{
    CopyText(reader, writer);
}

static void CopyText(TextReader reader, TextWriter writer)
{
    char[] buffer = new char[8192];
    int charsRead;
    while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
    {
        writer.Write(buffer, 0, charsRead);
    }
}

TextWriter実際にエンコーディングを変更しない限り、最初に/TextReaderペアを使用せずにこれを行うことができることに注意してください。

そうすれば、文字列全体とそのバイナリ表現( MemoryStream. もちろん、まだバイナリ表現を持っています-最初にすべてをに書き込む必要がありますMemoryStreamか?

于 2010-06-22T16:24:56.343 に答える
2

Jon が投稿した内容に加えて、.NET ランタイムが実際に動作する方法には、いくつかの重要な利点があります。システムのメモリが不足していない限り、プロセスに割り当てられたメモリを維持することは良いことです (この場合、ランタイムはおそらくメモリを解放します)。 )。

たとえば、(ここに投稿した方法のように) 大量のメモリを頻繁に割り当てる必要がある場合は、プロセスに既にメモリが割り当てられていると効率的です (.NET オブジェクトの格納に使用されていない場合でも)。 . 次回メソッドを実行すると、割り当てがはるかに高速になります。

とにかく、あなたができるいくつかのことは次のとおりです。

  • システムがメモリを必要とするときにランタイムがメモリを解放するかどうかを確認するために、別のメモリ集約型アプリケーションを実行してみてください。
  • .NET プロファイラーを使用して、メソッドの実行後に収集されると予想されるライブ オブジェクトがあるかどうかを確認できます。
于 2010-06-22T16:27:04.827 に答える
0

上記のセグメントではlog、 、reader、およびのすべてmemoryStreamがまだスコープ内にあるため、ガベージ コレクションを実行できません。これらのオブジェクトに対する の実装が何であるかはわかりませんが、が呼び出されDisposeた後でも、メモリ内に多くのデータを保持している可能性が非常に高いです(通常、 はファイル ハンドルやアンマネージ メモリなどを閉じるだけで、閉じないため)。必ずしも内部バッファーを削除する必要はありません)。これを期待どおりに動作させたい場合は、参照されているすべてのオブジェクトを範囲外にして参照されないようにする必要があります。DisposeDispose

ただし、実際には、メモリ使用量が明らかに苦痛を引き起こしている場合を除き、これについて心配する必要はありません。

于 2010-06-22T16:27:10.700 に答える
0

それが役立つかどうかはわかりませんが、usingスコープを試してみてください:

using (StreamReader reader = new StreamReader(somestream))
using (StreamWriter log = new StreamWriter("tempFile.txt"))
{
    log.Write(reader.ReadToEnd());
}
于 2010-06-22T16:25:33.917 に答える