web-dev-qa-db-ja.com

C#でメモリを明示的に解放する

主に大きな辞書が原因で、150MBのメモリ(プライベートバイト)を使用するC#アプリケーションを作成しました。

Dictionary<string, int> Txns = new Dictionary<string, int>();

このメモリを解放する方法を知りたいと思っていました。私はこれを試しました:

Txns = null;
GC.Collect();

しかし、それは私のプライベートバイトに大きな凹みを作るようには見えません-それらは、例えば155MBから145MBに落ちます。手がかりはありますか?

ありがとう

-編集-

さて、私はこのコードでもっと幸運を持っています(プライベートバイトを50mbに減らします)が、なぜですか?

Txns.Clear(); // <- makes all the difference
Txns = null;
GC.Collect();

-編集-

「GC.collectを使用しないでください」と言う人は大丈夫です(私のCの背景が見えてくると言う以外は議論しません)が、実際には私の質問には答えていません:トランザクションリストを最初にクリアすると、ガベージコレクターがメモリを解放するのはなぜですか?辞書は逆参照されているので、とにかくメモリを解放してはいけませんか?

37
Chris

プライベートバイトは、プロセスのメモリ使用量を反映します。オブジェクトが収集されると、関連するメモリセグメントがOSに解放される場合とされない場合があります。 CLRはメモリをOSレベルで管理します。メモリの割り当てと解放は無料ではないため、アプリケーションが後でさらにメモリを要求する可能性があるため、各メモリをすぐに解放する理由はありません。

18
Brian Rasmussen

gC.Collect()を呼び出すと、ジョブを開始しますが、すぐに戻りますが、ブロックしません。したがって、GC.WaitForPendingFinalizers()を呼び出しただけでは、GCまでアプリケーションをブロックします。 Collect()は仕事を終えます

11
Sadegh

ほとんどの場合、辞書の別の場所に隠された参照があります。したがって、辞書は収集されませんが、Clear()すると、コンテンツが収集されます。

他の人がすでに指摘しているように、GCを強制することはお勧めしません。これにより、メモリが頻繁に収集されないより高い「世代」にプッシュされる可能性があり、それにより長期的に得られるよりも多くのメモリが無駄になります。

5
David Schmitt

DictionaryDispose()があるかどうかはメモリからはわかりませんが、Clear()を持つ必要があります。 nullへの参照を設定する前に、これらのいずれかを呼び出します。

次に、単にガベージコレクターに処理を行わせます。ほとんどnever自分でGC.Collect()を明示的に呼び出すことは良い考えです。パフォーマンスが犠牲になります。静的コード分析(= FxCop)は、 信頼性ルールCA2001 について警告しません。あなたが何をしているかを本当に知っていない限り、単純にこれをしないでください。そして、それでもそれをしないでください。 ;-)

辞書がそんなに大きいと確信していますか?メモリは10 MBだけではなく、残りはアプリケーションによって使用されますか?あなたを助けるかもしれない質問:メモリが実際に消費されている場所を確認するためにプロファイラをまだ使用しましたか?

4
peSHIr

メモリを戻す必要がありますか?メモリは使用可能ですが、再生されていないだけです。ディクショナリをクリアせず、 weak reference を保持して、ランタイムにその仕事をさせてください。

何が起こっているのかを本当に詳しく知りたい場合は、 。NET Memory Profiler を確認してください。これにより、オブジェクトで何が起こっているのか、何が生成されているのか、どのメモリが何によって使用されているのかを正確に把握できます。 :)

1
JP Alioto

さて、ここに理論があります...辞書はKeyValuePairのコレクションであり、これも参照型です。

辞書には、これらのkeyValuePairsが含まれています。あなたが言う時:

Txns = null

これらのKeyValuePairコレクションから参照「Txns」を解放します。ただし、実際には150 Mbの実際のメモリがそれらのKeyValuePairによって参照されており、スコープ内にあるため、ガベージコレクションの準備ができていません。

ただし、次を使用する場合:

Txns.Clear();
Txns = null;
GC.Collect();

ここで、clearメソッドは、それぞれのKeyValuePairオブジェクト参照から150Mbのデータも解放します。したがって、これらのオブジェクトはガベージコレクションの準備ができていました。

私がここで作っているのはただのワイルドな推測です。コメントは大歓迎です:)

1
Savaratkar

編集:

公平を期すために、参照をnullに設定してもメモリは解放されず、コンテナが別のアドレス(この場合はnull)に割り当てられます。 [〜#〜] msdn [〜#〜] によると、Clear()を呼び出すと、「Countプロパティは0に設定され、他のオブジェクトへの参照はコレクションもリリースされます。容量は変わりません。」

...

ガベージコレクターを呼び出さないでください。ネイティブリソースのない管理対象オブジェクトを使用しています。ガベージコレクターを信頼して、クリーンアップしてください。

辞書のサイズに加えて、メモリについて心配する必要はありません。メモリはあなたの問題ではなく、ガベージコレクタの問題です。

Clear()を呼び出すと、内部に含まれるオブジェクトへの参照が削除されますが、容量は変更されません。

技術的な注意事項として、メモリの収集は高価であり、かなりの時間がかかります。理由は、GCがヒープメモリを処理してヒープをクリーンアップするだけでなく、ヒープを最適化するということでもあります。メモリの連続ブロックへの移動を試みて、コードの一部が大きなリクエストを行う場合の割り当てを高速化します。

追伸155MBのメモリを使用する辞書の大きさは?

1
Chris

通常、GCを強制しようとするのは良い考えではありません。辞書全体をメモリに保存する必要が本当にありますか?

0
ivmos

Windowsには2つのメモリ可用性イベントがあります。 CLRがこれに応答することを期待しています。使用可能なメモリが十分にある場合、スマートなことはガベージコレクタを実行しないことです。したがって、実際に悪いCLR動作を観察していることを確認するには、大きなメモリヒープを使用する別のダミーアプリケーションでこのテストを繰り返してください。

0
MSalters