私が正しく理解していれば、.netランタイムは常に私の後にクリーンアップされます。したがって、新しいオブジェクトを作成し、コードでそれらを参照するのをやめると、ランタイムはそれらのオブジェクトをクリーンアップし、それらが占有していたメモリを解放します。
これが事実なので、なぜいくつかのオブジェクトはデストラクタまたはdisposeメソッドを持っている必要がありますか?それらが参照されなくなったときに、ランタイムはそれらの後でクリーンアップしませんか?
私が正しく理解していれば、.netランタイムは常に私の後にクリーンアップされます。したがって、新しいオブジェクトを作成し、コードでそれらを参照するのをやめると、ランタイムはそれらのオブジェクトをクリーンアップし、それらが占有していたメモリを解放します。
これが事実なので、なぜいくつかのオブジェクトはデストラクタまたはdisposeメソッドを持っている必要がありますか?それらが参照されなくなったときに、ランタイムはそれらの後でクリーンアップしませんか?
ファイナライザーは、ファイルハンドル、ソケット、カーネルオブジェクトなど、不足しているリソースがシステムに解放されることを保証するために必要です。ファイナライザーは常にオブジェクトの寿命の終わりに実行されるため、これらのハンドルを解放するための指定された場所です。
このDispose
パターンは、リソースの決定論的破壊を提供するために使用されます。.netランタイムガベージコレクターは非決定論的であるため(つまり、ランタイムが古いオブジェクトを収集してそのファイナライザーを呼び出すタイミングがわからない)、システムリソースの決定論的リリースを保証するメソッドが必要でした。したがって、Dispose
パターンを適切に実装すると、リソースの決定論的なリリースが提供され、コンシューマーが不注意でオブジェクトを破棄しない場合、ファイナライザーがオブジェクトをクリーンアップします。
Dispose
必要な理由の簡単な例は、迅速でダーティなログメソッドです。
public void Log(string line)
{
var sw = new StreamWriter(File.Open(
"LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None));
sw.WriteLine(line);
// Since we don't close the stream the FileStream finalizer will do that for
// us but we don't know when that will be and until then the file is locked.
}
上記の例では、ガベージコレクターがオブジェクトのファイナライザーを呼び出すまで、ファイルはロックされたままになりStreamWriter
ます。その間、ログを書き込むためにメソッドが再度呼び出される可能性があるため、これには問題がありますが、ファイルがまだロックされているため、今回は失敗します。
正しい方法は、オブジェクトの使用が終了したときにオブジェクトを破棄することです。
public void Log(string line)
{
using (var sw = new StreamWriter(File.Open(
"LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))) {
sw.WriteLine(line);
}
// Since we use the using block (which conveniently calls Dispose() for us)
// the file well be closed at this point.
}
ところで、技術的にファイナライザーとデストラクタは同じことを意味します。私はc#デストラクタを「ファイナライザ」と呼ぶことを好みます。そうしないと、C#とは異なり、決定論的であるC++デストラクタと人々を混同する傾向があるためです。
前の答えは良いですが、ここでもう一度重要な点を強調させてください。特に、あなたはそれを言いました
私が正しく理解していれば、.netランタイムは常に私の後にクリーンアップされます。
これは部分的に正しいだけです。実際、.NETは、メインメモリという1つの特定のリソースの自動管理のみを提供します。他のすべてのリソースは手動でクリーンアップする必要があります。1)
奇妙なことに、メインメモリはプログラムリソースに関するほとんどすべての議論で特別なステータスを取得します。もちろん、これには十分な理由があります。メインメモリは、多くの場合、最も希少なリソースです。ただし、他の種類のリソースもあり、それらも管理する必要があることを覚えておく価値があります。
1)通常試みられる解決策は、他のリソースの存続期間をコード内のメモリ位置または識別子の存続期間に結合することです。したがって、ファイナライザーが存在します。
ガベージコレクタは、システムが実際にメモリを解放する必要がない限り、システムにメモリが不足していない場合にのみ実行されます。つまり、GCがいつ実行されるかを確認することはできません。
ここで、あなたがデータベース接続であると想像してください。後でGCをクリーンアップすると、データベースに必要以上に長く接続され、奇妙なロード状況が発生する可能性があります。その場合、IDisposableを実装して、ユーザーがDispose()を呼び出すか、using()を使用して、後で実行される可能性のあるGCに依存することなく、接続ができるだけ早く閉じられるようにします。
通常、IDisposableは、管理されていないリソースで動作するすべてのクラスに実装されます。
本当の理由は、.netガベージコレクションが管理されていないリソースを収集するように設計されていないためですしたがって、これらのリソースのクリーンアップは依然として開発者の手に委ねられています。また、オブジェクトがスコープ外になったときに、オブジェクトファイナライザーが自動的に呼び出されることはありません。それらは、未定の時間にGCによって呼び出されます。そして、それらが呼び出されると、GCはすぐにそれを実行せず、次のラウンドがそれを呼び出すのを待ち、クリーンアップする時間をさらに増やします。オブジェクトが管理されていないリソース(ファイルなど)をほとんど保持していない場合は、これは良いことではありません。またはネットワーク接続)。使い捨てパターンを入力します。開発者は、決められた時間に(yourobject.Dispose()またはusing(...)ステートメントを呼び出すときに)不足しているリソースを手動で解放できます。GC.SuppressFinalize(this);を呼び出す必要があることに注意してください。disposeメソッドで、オブジェクトが手動で破棄され、ファイナライズされるべきではないことをGCに通知します。K.CwalinaとB.AbramsによるFrameworkDesignGuidelinesの本をご覧になることをお勧めします。Disposableパターンが非常によく説明されています。
幸運を!
簡単な説明:
Finalizeメソッドを実装するためのいくつかのガイドライン:
Disposeメソッドを実装するためのいくつかのガイドライン:
デスクリュクタとdisposeメソッドを必要とするオブジェクトは、管理されていないリソースを使用しています。したがって、ガベージコレクタはこれらのリソースをクリーンアップできず、自分でこれを実行する必要があります。
IDisposableについてはMSDNのドキュメントを参照してください。http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
この例では、管理されていないハンドラーであるIntPrを使用しています。
一部のオブジェクトは、低レベルのアイテムをクリーンアップする必要がある場合があります。閉じる必要のあるハードウェアなど。
主に非マネージコード、および非マネージコードとの相互作用のため。「純粋な」マネージコードには、ファイナライザーは必要ありません。一方、使い捨ては、使い終わったときに何かを強制的に解放するための便利なパターンです。
.NETガベージコレクターは、.NETランタイム内で管理対象オブジェクトを処理する方法を知っています。ただし、Disposeパターン(IDisposable)は、主にアプリケーションが使用している管理対象外のオブジェクトに使用されます。
言い換えると、.NETランタイムは、すべての種類のデバイスを処理する方法や、そこで処理する方法(ネットワーク接続、ファイルハンドル、グラフィックスデバイスなどを閉じる)を必ずしも知っているわけではないため、IDisposableを使用すると、「タイプに「独自のクリーンアップを実装する」。その実装を確認すると、ガベージコレクターはDispose()を呼び出して、管理対象ヒープの外部にあるものが確実にクリーンアップされるようにすることができます。
純粋な管理対象オブジェクトが使用されなくなったときに特定のアクションを実行する必要がある場合がいくつかあります(ごくわずかです)。頭のてっぺんから例を思い付くことができませんが、いくつか見ました。長年にわたる合法的な使用の。ただし、主な理由は、オブジェクトが使用している可能性のある管理されていないリソースをクリーンアップすることです。
したがって、一般に、管理されていないリソースを使用している場合を除き、Dispose/Finalizeパターンを使用する必要はありません。
ガベージコレクターは、管理対象環境が割り当てなかったものを収集できないためです。したがって、メモリ割り当てをもたらすアンマネージAPIの呼び出しは、従来の方法で収集する必要があります。