2

C#変数は、型が宣言されている場所(たとえばstring s;)でインスタンス化され、現在のスコープの閉じ中括弧で解放されます。

// Operates with Q memory
void FantasyMethod() {
    var o = new BigObject();

    {
        var temp = new BigObject();
        Populate(temp); // Populates o1 with N megabytes of data

        o = PerformSomeOperationsOn(temp); // Returns a BigObject of size M (M is close to N)

        // Currently, M+N memory is occupied, we have Q-M-N free
    }

    // Let's tell the garbage collector to catch up
    GC.Collect();
    GC.WaitForPendingFinalizers();

    // Currently, M memory is occupied

    DoUsefulStuffWith(o); // This method can only work if at least Q-M-N/2 memory is free
}

これの利点の1つは、関数が戻る前に大きな変数を解放できることです。上記の(些細な)ブロックでは、大きな変数が不要になったらすぐに破棄することで、限られた使用可能なメモリを使用しています。

  1. 上記は正しいですか?
  2. これを行うのは良い考えですか(私は個人的な意見や好みではなく、賛成と反対の議論に興味があります)?メソッドとしてネイキッドブレースブロックを抽出すると、メモリの使用効率が低下しますか?読みやすさの理由で新しいメソッドを作成したくない場合はどうなりますか?
4

4 に答える 4

5

これの利点の1つは、関数が戻る前に大きな変数を解放できることです。

いいえ。C#はC ++ではなく、オブジェクトにはデストラクタがありません。また、オブジェクトが宣言スコープを離れ、オブジェクトへの有効な参照が存在しない場合に、オブジェクトが再利用される保証はありません。

そのレベルの予測可能性が必要な場合は、管理された言語、期間を使用するべきではありません。C#のメモリプレッシャーを軽減するのに役立つ手法は存在しますが、それらが必要になることはあまりなく、CやC++などの言語が提供するレベルの制御を取得することはできません。

あなたの編集ごとに:

GC.CollectはGCパスの実行を試みますが、それを保証するものではありません。 GC.WaitForPendingFinalizersは、ファイナライズのマークが付けられたすべてのオブジェクトがファイナライザーを実行するまでブロックします。

オブジェクトがファイナライザーを実装し、SuppressFinalizeを呼び出してファイナライズを無効にしていない場合、オブジェクトはファイナライズの準備ができているとマークされたオブジェクトのリストに配置されます。ガベージコレクタは、このリスト内のオブジェクトのFinalizeメソッドを呼び出し、リストからエントリを削除します。このメソッドは、すべてのファイナライザーが完了するまでブロックされます。

于 2012-09-11T23:24:23.263 に答える
2

あなたの推定は完全に正しいわけではありません。C ++とは異なり、オブジェクトがスコープ外にある場合、オブジェクトはすぐには破棄されません(または、ペダンティックになりたい場合は、デストラクタが呼び出されます)。保証できるのは、閉じたスコープ内でインスタンス化されたオブジェクトを指す参照がまったくないときにGCスイープが発生した場合、オブジェクトが収集されるということだけです。

また、オブジェクトの使用を明示的なスコープ内に含めなくても、コンパイラは、オブジェクトが使用/参照されていないことを「知る」ための十分な情報をすでに持っているので、それを好むことはありません。

于 2012-09-11T23:29:34.277 に答える
0

BigObjectが値型ではないと仮定すると、これは正しくありません。がクラスの場合BigObject、それは常にマネージヒープに存在し、スコープから外れた後に決定論的に破棄されることはありません。GCは別のスレッドで実行され、いつ収集を行うかを予測することはできません。

于 2012-09-11T23:25:18.770 に答える
0

ブロック内に変数を配置すると変数が解放されるとは聞いたことがありません。また、解放とはどういう意味ですか?メモリはガベージコレクタによって管理され、メモリを解放するタイミングを決定します。

「変数」がリソースを保持している場合は、IDisposableを実装する必要があります。http://msdn.microsoft.com/en-us/library/system.idisposable.aspx)、次のようになります。

using (var b = new DisposableObject())
{
   ...
}
于 2012-09-11T23:28:24.713 に答える