using ステートメントを使用しない場合、IDisposable のメモリ リークは発生しますか?
もしそうなら、コードがあまりない場合、誰かがメモリリークの例を提供できますか?
6 に答える
を実装する型のインスタンスを作成し、放棄されたときにそれ自体を適切にクリーンアップできることが明確に知られIDisposable
ていない、正しく作成されたプログラムは、放棄する前にそのインスタンスで が呼び出されることを確認する必要があります。それがなくても問題ないことが明確に知られていない型の呼び出しに失敗したプログラムはすべて壊れています。Dispose
Dispose
自動ファイナライズですべて処理できればいいのですが、クリーンアップ メカニズムはかなり厄介です。順序付け、スレッド化コンテキスト、適時性、または完了の確実性に関しては保証されません (決定論的クリーンアップを使用する場合、クリーンアップが失敗した場合にプログラムが正常に完了しないように見えることを合理的に確認できます。ファイナライズを使用する場合、プログラムはオブジェクトのクリーンアップを試みることなく、正常に完了したように見えます)。
Microsoft はかつて、すべてIDisposable
のクラスが放棄された場合に適切にクリーンアップできるようにすることを意図していたかもしれませんが、それは実際的ではありません。多くの場合、クラスが放棄された場合にそれ自体をクリーンアップしようとすると、膨大な量の複雑さが追加され、追跡が容易な明らかな問題がある壊れたプログラムが、通常は機能する壊れたプログラムに変わるだけです。ただし、他のスレッドに対するファイナライザー スレッドのタイミングによって、予期しない再現性のない方法で問題が発生する場合は除きます。
IDisposable
を実装しているにもかかわらず、無条件に放棄しても安全なタイプもあれば、特定の状況で安全に放棄できるタイプもあります。そのような型を破棄するのが難しい状況では、そのような型を放棄しても問題ありません (たとえば、さまざまなスレッドによって操作される複数のオブジェクトによって参照が保持されており、特定のオブジェクトが最後に生き残った型を保持しているときにそれを知る良い方法がないため)。ただし、そのような行動が安全かつ適切であると信じる理由を文書化することを条件とします。IDisposable
しかし、そのような振る舞いは、未知の系統のオブジェクトを受け入れた場合には適切ではありません.
いいえ、漏れません。最終的に、ガベージ コレクションはオブジェクトの破棄に回ります。
IDisposable
呼び出し元がリソースを早期に解放できるようにします。
アップデート
@Servy と @Brian Rasmussen が述べているように。を実装するクラスはIDisposable
、ファイナライザーも実装する必要があります。これは推奨される方法です。http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.100).aspxを参照してください。
まず、IDisposable は通常、外部の管理されていないリソース1 (ファイル、接続など) とそれらのリークに関連していることに注意してください。これらによって使用される CLR オブジェクトとメモリは、到達可能性に基づいて GC によって引き続き正しく処理されます。
IDisposable はコントラクトを定義し、型への追加または型からの削除時に破壊的変更を表します。この契約を尊重しないと、「明確に定義されていない動作」が発生する可能性があります。コンストラクトは、Dispose の呼び出しの詳細と例外を伴うエッジ ケースを処理する必要を回避するためのusing
ツールですが、コントラクトの一部ではなく、必須ではありません。それでも、契約は同じままであり、そのような違反は、前述の IDisposable が「正しく機能する」というすべての責任を取り除きます。
- IDisposable を実装する一部の型は、リソースをリークしません。外部リソースを破棄しない場合があります。
- IDisposable を実装する一部の型は、ファイナライザーも実装するという "ベスト プラクティス" に従っていません。Dispose が呼び出されない場合、外部リソースがリークします。
- ファイナライザー パターンも実装する型など、一部の型は、特定の GC 状況でのみ外部リソースをリークする可能性があります。つまり、ファイナライザーがすぐに呼び出されない可能性があります。この状態は、低負荷のシナリオでは遅すぎて問題にならない可能性がありますが、高負荷のシナリオでは予期しない障害につながる可能性があります。
- 一部のタイプでは、動作が不明確で状態が一貫していない状況が発生する可能性があります。
契約に違反しないでください。
1 IDisposable 型は、管理されていないリソースを利用しない Dispose の状態を変更することもできます。契約に違反した場合、これは「明確に定義されていない動作」でカバーされます。IDisposable 型を使用した 1 つのケースは、技術的にはランタイムによって "管理" されている場合でも、ランタイム呼び出し可能ラッパー (RCW) オブジェクトを管理することです。その他の状況については、スーパーキャットのコメントを参照してください。
それはすべてあなたが何であるかに依存しますIDisposable
。
パターンは基本的に、そのIDisposable
オブジェクトのファイナライザーが実行されるまで待機するのではなく、マネージド (およびアンマネージド) リソースを決定論的に解放する方法です。たとえば、データベース接続やファイル ハンドルなどを開く場合は、もちろん、これらのリソースを解放するか、「オンデマンド」でクリーンアップする必要があります。これは、Dispose
パターンの主な使用例です。
それで、それはメモリをリークしますか?IObervable<T>
サブスクリプションを使用している場合、サブスクリプションはリリースされていないイベント ハンドラーである可能性が非常に高いです(ここでは大幅に簡略化しています)。それを閉じないとメモリリークが発生しますSqlConnection
か?「メモリリーク」の最も厳密な定義によるものではありません。接続は最終的に閉じられるためです(たとえば、アプリが終了したとき、または接続オブジェクトが最終的に収集されてファイナライズされたときなど)。
「常に IDisposables を破棄してください」
編集:@Servyは絶対に正しいです-私のSqlConnection
例では、ファイナライザーが自動的に接続を閉じると思いますが、これはIDisposables
一般的に保証された動作ではありません-常に破棄してください!
using
ステートメントは単なる構文糖衣
using(var resource = expression) statement
好きなものを翻訳する
{
var resource = expression;
try {
statement;
}
finally {
[if(resource!=null)]((IDisposable)resource).Dispose();
}
}
Dispose パターンが正しく実装されていれば、メモリ リークは発生しません。メソッドFinalizer
を呼び出すGC 呼び出し (非決定論的) 。Dispose
Using
ステートメントはDispose
、ブロックの最後でオブジェクト メソッドを呼び出します。
次の例を使用して同じ結果を得ることができます。
obj a = new obj(); // Assuming obj : IDisposable
try
{
// Your code here
}
finally
{
if (a != null)
{
a.Dispose();
}
}