質問

読んでいた これ 先日の記事で、なぜ Dispose メソッドと一緒に Finalizer があるのか​​疑問に思いました。私は読む ここ ファイナライザーに Dispose を追加する理由について説明します。私の興味は、Dispose メソッド自体に対して Finalizer がいつ呼び出されるのかということです。コード例はありますか、それともソフトウェアが実行されているシステムで起こっていることに基づいていますか?その場合、GC によって Dispose メソッドが実行されないことが起こります。

役に立ちましたか?

解決

ここでのファイナライザーの目的は、単にメモリ リークに対する安全対策です (メモリ リークが発生した場合)。 ない 電話する Dispose 明示的に)。また、プログラムのシャットダウン時にオブジェクトにリソースを解放させたい場合、オブジェクトを破棄する必要がないことも意味します。これは、いずれにせよ GC が強制的にすべてのオブジェクトをファイナライズして収集するためです。

関連する点として、ファイナライザーからオブジェクトを処理する場合は、少し異なる方法でオブジェクトを処理することが重要です。

~MyClass()
{
    Dispose(false);
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected void Dispose(disposing)
{
    if (!this.disposed)
    {
        if (disposing)
        {
            // Dispose managed resources here.
        }
        // Dispose unmanaged resources here.
    }
    this.disposed = true;
}

あなたがその理由 しないでください ファイナライザーでマネージド リソースを破棄したい場合は、実際にその際にマネージド リソースへの強い参照を作成することになり、GC が適切にジョブを実行してリソースを収集できなくなる可能性があります。管理されていないリソース (例:Win32 ハンドルなど) は、CLR がそれらを認識しないため、常に明示的に閉じたり破棄したりする必要があります。

他のヒント

これは主に自分自身を守るためにあります。クラスのエンドユーザーが何をするかを指示することはできません。Dispose メソッドに加えてファイナライザーを提供すると、ユーザーが Dispose() を呼び忘れたり、クラスを誤って使用したりした場合でも、GC はオブジェクトを「破棄」し、リソースを適切に解放します。

Finalizer は、オブジェクトがガベージ コレクションされるときに呼び出されます。Dispose を明示的に呼び出す必要があります。次のコードでは、ファイナライザーが呼び出されますが、Dispose メソッドは呼び出されません。

class Foo : IDisposable
{
  public void Dispose()
  {
    Console.WriteLine("Disposed");
  }

  ~Foo()
  {
    Console.WriteLine("Finalized");
  }
}

...

public void Go()
{
  Foo foo = new Foo();
}

Dispose() を呼び出すか、using ステートメントにオブジェクトを含めることによって、dispose メソッドを明示的に呼び出す必要があります。GC は常にファイナライザーを呼び出すため、オブジェクトが破棄される前に何かを行う必要がある場合、ファイナライザーは少なくともオブジェクト内のすべてがクリーンアップされていることを確認する必要があります。

ファイナライザーでのオブジェクトのクリーンアップは、可能であれば避けたいと思います。これは、事前にオブジェクトを破棄する場合 (dispose を呼び出すなど) に比べて余分な作業が発生するためです。ただし、必要なオブジェクトが周囲に存在するかどうかを、少なくともファイナライザーで常にチェックする必要があります。削除されます。

重要だが微妙な注意点がまだ言及されていません:Dispose の目的はあまり考慮されませんが、オブジェクトが時期尚早にクリーンアップされるのを防ぐことです。ファイナライザが実行されないように、ファイナライザを含むオブジェクトは慎重に記述する必要があります 以前 予想以上に。ファイナライザーは、オブジェクト (*) に対して行われる最後のメソッド呼び出しの開始前に実行できませんが、実行される場合があります。 その間 メソッドが完了するとオブジェクトが破棄される場合は、最後のメソッド呼び出し。オブジェクトを適切に Dispose するコードは、Dispose を呼び出す前にオブジェクトを破棄できないため、Dispose を適切に使用するコードにファイナライザーが大混乱を引き起こす危険はありません。一方、オブジェクトを使用する最後のメソッドが、オブジェクト参照自体を最後に使用した後にファイナライザーでクリーンアップされるエンティティを利用する場合、ガベージ コレクターがオブジェクトに対して Finalize を呼び出してクリーンアップすることが可能です。まだ使用されているエンティティをアップします。解決策は、ファイナライザーによってクリーンアップされるエンティティを使用する呼び出しメソッドの後に、ある時点で "this" を使用するメソッド呼び出しが続く必要があることを確認することです。GC.KeepAlive(this) は、そのために使用する良いメソッドです。

(*) オブジェクトに対して何も実行しないインライン コードに展開される非仮想メソッドは、このルールから除外される場合がありますが、通常、Dispose は仮想メソッドであるか、仮想メソッドを呼び出します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top