111

私は CLR と GC の仕組みに魅了されています (C# を介して CLR を読んだり、Jon Skeet の書籍や投稿などを読んだりして、これに関する知識を広げようとしています)。

とにかく、言うことの違いは何ですか:

MyClass myclass = new MyClass();
myclass = null;

または、MyClass に IDisposable とデストラクタを実装させ、Dispose() を呼び出すことによって?

また、using ステートメント (以下など) を含むコード ブロックがある場合、コードをステップ実行して using ブロックを終了すると、オブジェクトは破棄されますか、それともガベージ コレクションが発生したときに破棄されますか? とにかく、using ブロックで Dispose() を呼び出すとどうなりますか?

using (MyDisposableObj mydispobj = new MyDisposableObj())
{

}

ストリーム クラス (BinaryWriter など) には Finalize メソッドがありますか? なぜそれを使いたいのですか?

4

3 に答える 3

223

廃棄をガベージ コレクションから分離することが重要です。それらは完全に別個のものですが、1 つの共通点があります。これについては後で説明します。

Dispose、ガベージ コレクションとファイナライズ

ステートメントを書くときusing、それは単に try/finally ブロックのシンタックス シュガーであるため、ステートメントの本体のコードが例外をスローDisposeした場合でも呼び出されます。オブジェクトがブロックの最後でガベージ コレクションされるという意味ではusingありません。

廃棄は、管理されていないリソース(メモリ以外のリソース) に関するものです。これらは、UI ハンドル、ネットワーク接続、ファイル ハンドルなどである可能性があります。これらは限られたリソースであるため、通常はできるだけ早く解放する必要があります。IDisposableタイプがアンマネージ リソースを直接 (通常は を介し​​てIntPtr) または間接的に (たとえば、Stream、 aなどを介して) 「所有」する場合はいつでも実装する必要がありますSqlConnection

ガベージ コレクション自体はメモリに関するものにすぎません。ガベージ コレクターは、参照できなくなったオブジェクトを見つけて解放することができます。ただし、常にガベージを探すわけではありません - ガベージが必要であることを検出した場合のみです (たとえば、ヒープの 1 つの「世代」でメモリが不足した場合)。

ツイストはファイナライズです。ガベージ コレクターは、もはや到達可能ではないが、ファイナライザーを持っているオブジェクトのリストを保持します ( ~Foo()C# のように記述されているため、やや紛らわしいですが、C++ のデストラクタとはまったく異なります)。メモリが解放される前に余分なクリーンアップを行う必要がある場合に備えて、これらのオブジェクトでファイナライザーを実行します。

ファイナライザーは、ほとんどの場合、型のユーザーが規則正しい方法で破棄するのを忘れた場合に、リソースをクリーンアップするために使用されます。したがって、 a を開いたときにorFileStreamを呼び出すのを忘れた場合、ファイナライザーは最終的に基になるファイル ハンドルを解放します。私の意見では、適切に作成されたプログラムでは、ファイナライザーが起動することはほとんどありません。DisposeClose

変数の設定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、ループ内にあり、ループのいくつかの分岐で変数を使用する必要があるが、使用しないポイントに到達したことがわかっている場合です。例えば:

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は、あなたの友人です-使い始めるのに少し時間がかかりますが、ファイナライザーを再度作成する必要はほとんど ないことを意味します. 通常、リソース ( ) を実際に直接処理する場合にのみファイナライザーが必要であり、IntPtrSafeHandleできるだけ早くすることができますように。(そこには 2 つのリンクがあります - 理想的には両方を読んでください。)

Joe Duffy は、ファイナライザーと IDisposable (多くの賢い人々と共同で作成) に関する非常に長い一連のガイドラインを持っており、読む価値があります。クラスを封印すると、生活がずっと楽になることに注意してください。Dispose新しい仮想メソッドなどを呼び出すためのオーバーライドのパターンはDispose(bool)、クラスが継承用に設計されている場合にのみ関連します。

これは少しとりとめのないものでしたが、どこに欲しいのか明確にしてください:)

于 2009-02-22T09:47:51.360 に答える
22

オブジェクトを破棄すると、リソースが解放されます。変数に null を割り当てると、参照が変更されるだけです。

myclass = null;

これを実行した後、myclass が参照していたオブジェクトはまだ存在し、GC がそれをクリーンアップするまで継続します。Dispose が明示的に呼び出された場合、またはそれが using ブロック内にある場合、リソースはできるだけ早く解放されます。

于 2009-02-22T00:31:53.833 に答える
8

2つの操作は互いにあまり関係がありません。参照をnullに設定すると、それは単にそれを行います。それ自体は、参照されたクラスにはまったく影響しません。変数は、以前のオブジェクトを指していませんが、オブジェクト自体は変更されていません。

Dispose()を呼び出すと、それはオブジェクト自体のメソッド呼び出しになります。Disposeメソッドが行うことは何でも、オブジェクトに対して実行されるようになりました。ただし、これはオブジェクトへの参照には影響しません。

重複する唯一の領域は、オブジェクトへの参照がなくなると、最終にガベージコレクションが行われることです。また、クラスがIDisposableインターフェイスを実装している場合、ガベージコレクションが行われる前に、オブジェクトに対してDispose()が呼び出されます。

ただし、2つの理由から、参照をnullに設定した直後は発生しません。まず、他の参照が存在する可能性があるため、まだガベージコレクションは行われません。次に、それが最後の参照であったとしても、ガベージコレクションの準備ができているため、ガベージコレクターが削除を決定するまで何も起こりません。オブジェクト。

オブジェクトに対してDispose()を呼び出しても、オブジェクトが「強制終了」されることはありません。これは通常、オブジェクトを後で安全に削除できるようにクリーンアップするために使用されますが、最終的には、Disposeには魔法のようなものはなく、単なるクラスメソッドです

于 2009-02-22T00:58:02.677 に答える