3

このコードを想像してください:

int i=9999999;
while ( i > 1 )
{
    string UnusedMemory="this is a string that eats some ram" + i.ToString();
    i--;
}

の実行時に参照されていないオブジェクトが時々削除される場合GC.Collect()、このコードは収集が行われるまで大量の RAM を割り当てる必要があります。しかし、巨大なメモリをまったく割り当てません。なぜですか? ILレベルで実装されたある種の「削除」はありますか? またはGC.Collect()、自動的に呼び出されるのが速くなりますか? これは些細な例であることはわかっていますが、より複雑で、そのコード ブロックで文字列がアクセスされた場合でも、多くの RAM を消費することはありません。

編集:文字列が常に一意になるように例を変更して、「キャッシュ」できないようにしました

4

2 に答える 2

8

文字列定数は文字列プールに「キャッシュ」されるため、毎回同じ文字列になります。

文字列に対してメソッドを使用すると、プールに含まれていることを意味するString.IsInternedが返されます。true

String.IsInternedから:

共通言語ランタイムは、インターン プールと呼ばれるテーブルを自動的に維持します。このテーブルには、プログラムで宣言された一意の各リテラル文字列定数の 1 つのインスタンスと、プログラムで追加した String の一意のインスタンスが含まれます。

インターン プールは、文字列ストレージを節約します。リテラル文字列定数を複数の変数に割り当てる場合、各変数は、同じ値を持つ String の複数の異なるインスタンスを参照するのではなく、インターン プール内の同じ定数を参照するように設定されます。

さらに、GC はメモリが必要な場合や十分な要素が割り当てられた場合に自動的に呼び出されるため、文字列がキャッシュされていなくても問題ありません。

ガベージ コレクションの基礎から:

ガベージ コレクションは、次の条件のいずれかに該当する場合に発生します。

  • システムの物理メモリが不足しています。
  • マネージ ヒープ上の割り当てられたオブジェクトによって使用されるメモリが、許容可能なしきい値を超えています。これは、マネージ ヒープで許容可能なメモリ使用量のしきい値を超えたことを意味します。このしきい値は、プロセスの実行中に継続的に調整されます。
  • GC.Collect メソッドが呼び出されます。ほとんどの場合、ガベージ コレクタは継続的に実行されるため、このメソッドを呼び出す必要はありません。この方法は、主に固有の状況とテストに使用されます。

この動作を変更または最適化することは可能ですか? はい、ある程度:レイテンシーモード

この質問は、for ループでオブジェクトを作成するための C# メモリ使用量に非常に関連し ています。

于 2013-04-06T09:52:09.293 に答える
3

オブジェクトがヒープから割り当てられ、十分な空き領域がない場合、ガベージ コレクターが実行されます。最初のヒープのコレクションが十分なメモリを解放しない場合、次のレベルのヒープでコレクションを続行します。すべてのヒープを収集しても十分なメモリが解放されない場合にのみ、システムからより多くのメモリが割り当てられます。

あなたの例には最近解放されたオブジェクトがたくさんあるので、最初のヒープのコレクションは常に十分なメモリを解放します。ループはヒープを数回埋めます。ループの前後を印刷してGC.CollectionCount(0)、ループが何回実行されたかを確認できます。

于 2013-04-06T10:09:15.270 に答える