処理をガベージコレクションから切り離すことは重要です。それらは完全に別のもので、1つのポイントが共通しています。
Dispose
、ガベージコレクションとファイナライズ
あなたがusing
文を書くときDispose
はusing
文の本体のコードがスローた場合でも呼び出されるように、それはのtry/finallyブロックのために、単純にシンタックスシュガーです例外。それはではありませんは、オブジェクトがブロックの最後にガベージコレクションされていることを意味します。
廃棄は約アンマネージドリソース(非メモリリソース)です。これらは、UIハンドル、ネットワーク接続、ファイルハンドルなどである可能性があります。これらのリソースは限られているため、できるだけ早く解放したいと考えています。直接(通常IntPtr
を介して)または間接的に(たとえばStream
、SqlConnection
などを介して)いずれかのタイプがアンマネージドリソースを「所有」している場合は必ずIDisposable
を実装する必要があります。
ガーベジコレクション自体は、メモリについてのものです。ガベージコレクタは参照できなくなったオブジェクトを見つけ出し、解放することができます。しかし、ヒープが必要なことを検出したときだけ(例えば、ヒープの「世代」がメモリ不足の場合)、常にガベージが検索されることはありません。
ひねりはファイナライゼーションです。ガベージコレクタは、もはや到達可能ではなく、ファイナライザを持つオブジェクトのリストを保持しています(C#では~Foo()
と書かれていますが、C++デストラクタのようなものではありません)。メモリが解放される前に余分なクリーンアップを行う必要がある場合に備えて、これらのオブジェクトのファイナライザを実行します。
ファイナライザは、ほとんどの場合、タイプのユーザが整然とした方法で処分するのを忘れた場合にリソースをクリーンアップするために使用されます。したがって、FileStream
を開いてもDispose
またはClose
に電話するのを忘れた場合、ファイナライザはとなり、最終的にがあなたのためにファイルハンドルを解放します。よく書かれたプログラムでは、finalizersはほとんど私の意見では決して発射すべきではありません。
null
に変数を設定するに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
にローカル変数を設定すると、あなたがループにいるときであり、ループのいくつかの枝が変数を使用する必要がありますが、あなたを知っている価値があるかもしれない1時間あなたがしていないポイントに達しました。たとえば:
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を/ファイナライザ
だから、あなた自身のタイプは、ファイナライザを実装する必要がありますか?ほとんど間違いない。 間接的にの場合は、アンマネージドリソース(例:あなたはFileStream
をメンバ変数として持っています)あなた自身のファイナライザを追加することは助けになりません:あなたのオブジェクトがストリームの場合、ストリームはガベージコレクションの対象になりますので、ファイナライザを持つFileStream
に頼ることができますそれは他のものを参照するかもしれない、など)。管理されていないリソースを「ほぼ」直接保持したい場合は、SafeHandle
があなたの友人です。これに行くには少し時間がかかりますが、almostnever need to write a finalizer againとなります。できるだけ早くリソースのハンドル(IntPtr
)を持っていれば、通常はファイナライザが必要です。できるだけ早くSafeHandle
に移動してください。
ジョーダフィーは、読む価値があるvery long set of guidelines around finalizers and IDisposable(たくさんのスマートフォークと共同編集)を持っています。クラスを封印すると、より簡単になります。新しい仮想Dispose(bool)
メソッドなどを呼び出すために、Dispose
をオーバーライドするパターンは、クラスが継承のために設計されている場合にのみ関係します。
これは、散歩の少しでしたが、あなたには、いくつかのようにしたいところ明確化を依頼してください:)
Re: "ローカル変数をnullに設定する価値があるかもしれません" - おそらく、より厄介な "キャプチャ"シナリオ(同じ変数の複数のキャプチャ) - しかし、ポストを複雑にする価値はないかもしれません! +1 ... –
@Marc:それは本当です - 私はキャプチャされた変数についても考えていませんでした。うーん。ええ、私はそれを残すだろうと思う;) –
うわー。私は最終的に、Skeetistsのカルトの源を理解します。この投稿は素晴らしいです! – JohnFx