ガベージコレクションから廃棄を分離することが重要です。これらは完全に別のものであり、共通点が1つあります。
Dispose
、ガベージコレクションとファイナライズ
using
ステートメントを記述する場合、それはtry / finallyブロックの構文上の糖衣でDispose
あり、using
ステートメントの本文のコードが例外をスローした場合でも呼び出されます。これは、オブジェクトがブロックの最後でガベージコレクションされることを意味するものではありません。
破棄は、アンマネージリソース(非メモリリソース)に関するものです。これらは、UIハンドル、ネットワーク接続、ファイルハンドルなどです。これらは限られたリソースであるため、通常はできるだけ早く解放する必要があります。あなたは、実装する必要がありますIDisposable
あなたのタイプは、管理対象外のリソースを「所有」するたびに(通常経由で直接いずれかで、IntPtr
(例えばビア間接的に)またはStream
、A SqlConnection
など)。
ガベージコレクション自体はメモリに関するものだけです-少しひねりを加えます。ガベージコレクターは、参照できなくなったオブジェクトを見つけて解放することができます。ただし、常にガベージを検索するわけではありません。必要なことが検出された場合のみです(たとえば、ヒープの1つの「世代」がメモリ不足になった場合)。
ひねりはファイナライズです。ガベージコレクターは、到達できなくなったがファイナライザーを備えたオブジェクトのリストを保持します(~Foo()
C#のように書かれていますが、混乱を招きます-それらはC ++のデストラクタには似ていません)。メモリが解放される前に余分なクリーンアップを行う必要がある場合に備えて、これらのオブジェクトに対してファイナライザを実行します。
ファイナライザは、ほとんどの場合、そのタイプのユーザーが通常の方法で破棄するのを忘れた場合に、リソースをクリーンアップするために使用されます。そのため、を開くFileStream
がDispose
orの呼び出しを忘れた場合Close
、ファイナライザは最終的に基になるファイルハンドルを解放します。よく書かれたプログラムでは、ファイナライザはほとんど私の意見では発動しないはずです。
変数を null
変数を設定する際の1つの小さなポイントnull
-これは、ガベージコレクションのためにほとんど必要ありません。それがメンバー変数である場合、それを実行したい場合がありますが、私の経験では、オブジェクトの「一部」が不要になることはまれです。ローカル変数の場合、JITは通常、(リリースモードで)十分に賢く、参照を再び使用しない場合を認識します。例えば:
StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();
// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);
// These aren't helping at all!
x = null;
sb = null;
// Assume that x and sb aren't used here
それは一度もローカル変数を設定する価値があるが、null
あなたがループにいるときで、変数を使用するループの必要性のいくつかの支店がありますが、あなたがそうでない時点に達した知っています。例えば:
SomeObject foo = new SomeObject();
for (int i=0; i < 100000; i++)
{
if (i == 5)
{
foo.DoSomething();
// We're not going to need it again, but the JIT
// wouldn't spot that
foo = null;
}
else
{
// Some other code
}
}
IDisposable / finalizerの実装
それで、あなた自身のタイプはファイナライザを実装すべきですか?ほとんど間違いなくそうではありません。アンマネージリソースのみを間接的に保持している場合(たとえばFileStream
、メンバー変数としてを持っている場合)、独自のファイナライザーを追加しても効果がありません。オブジェクトが存在する場合、ストリームはほぼ確実にガベージコレクションの対象になるので、FileStream
ファイナライザを持っている(必要な場合-それは他のものを参照するなど)。アンマネージリソースを「ほぼ」直接保持したい場合、それSafeHandle
はあなたの友人です-始めるのに少し時間がかかりますが、ファイナライザを再度記述する必要はほとんどあり ません。通常、ファイナライザが必要になるのは、リソース(IntPtr
)を本当に直接処理していて、次の場所に移動する場合だけです。SafeHandle
できるだけ早くすることができますように。(そこには2つのリンクがあります-理想的には両方を読んでください。)
Joe Duffyには、ファイナライザとIDisposable(多くのスマートフォークで共同作成)に関する非常に長い一連のガイドラインがあり、読む価値があります。クラスをシールすると、人生が非常に簡単になることに注意してください。Dispose
新しい仮想Dispose(bool)
メソッドなどを呼び出すためのオーバーライドのパターンは、クラスが継承用に設計されている場合にのみ関係します。
これは少しばかげていますが、どこに行きたいかを明確に尋ねてください:)