9

言い換えると、

class Foo
{
    object obj;
    Foo() { obj = new object(); }
    ~Foo() { obj.ToString(); /* NullReferenceException? */ }
}
4

5 に答える 5

7

objはすでにガベージコレクションされている可能性があるため、安全ではありません。また、ガベージコレクターは参照をnullに設定しないことに注意してください。したがって、obj!=nullをチェックしても役に立ちません。

詳細については、こちらをご覧ください:http: //msdn.microsoft.com/en-us/magazine/cc163392.aspx#S3

この原則を一般化すると、Disposeメソッドでは、管理対象オブジェクトかネイティブリソースかに関係なく、オブジェクトが保持しているすべてのリソースを安全にクリーンアップできます。ただし、ファイナライザーでは、ファイナライズできないオブジェクトのみをクリーンアップできます。通常、ファイナライザーはネイティブリソースのみをリリースする必要があります。 "(オブジェクトはファイナライズ可能であるため、別のファイナライザーでタッチしないでください)

それはあなたが持っている理由でもあります

if(disposed){...}

IDisposableパターンで(上記のリンクの図2を参照)。

于 2010-02-24T16:26:25.023 に答える
7

Object.Finalizeから:

2 つのオブジェクトのファイナライザーは、一方のオブジェクトが他方のオブジェクトを参照している場合でも、特定の順序で実行されるとは限りません。つまり、オブジェクト A にオブジェクト B への参照があり、両方にファイナライザーがある場合、オブジェクト A のファイナライザーが開始されたときに、オブジェクト B は既にファイナライズされている可能性があります。

要するに、ファイナライザー中に参照されるオブジェクトの状態について何の仮定も立てることはできません。

ほとんどすべての状況で、ファイナライザーに実装されたロジックは Disposable パターンに属します。これは、 IDisposableインターフェイスを使用して .NET でパターンを正しく実装する方法の例です。

public class MyClass : IDisposable
{
    private bool _disposed;

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

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if(disposing)
            {
                // Release unmanaged resources.
            }

            // Release managed resources (Streams, SqlConnections, etc.)
        }

        _disposed = true;
    }
}

万一アンマネージ リソースを操作している場合は、この記事を参照しIDisposableて、ファイナライザーを使用して実装する方法を確認してください。

MDSN: アンマネージ リソースをクリーンアップするための Finalize と Dispose の実装

于 2010-02-24T16:21:10.213 に答える
3

オブジェクトがファイナライズに登録されると、ファイナライズ キューに配置されます。ガベージ コレクターが実行されると、すべてのオブジェクトが次の 3 つのカテゴリに分類されます。

  1. ファイナライズ キュー 以外のルート化されたライブ参照を持つもの。
  2. 唯一のルート化された参照がファイナライズ キューである もの。
  3. ルート化された参照が存在しないもの。

3 番目のタイプのオブジェクトは存在しなくなりますが、何も気付かれることはありません。最初のタイプのものは「ライブ」と見なされます。中間タイプのもの (ファイナライザーを持つオブジェクト、およびファイナライズ可能なオブジェクトが参照を保持するその他のオブジェクトを含む) では、ファイナライザー (存在する場合) が実行されます。ファイナライザーが完了すると、ファイナライザーがルート化された参照をどこかに保存するか、ファイナライズのためにオブジェクトを再登録しない限り、オブジェクトはルート化された参照をまったく持たなくなり、次のガベージ コレクションの対象となります。

ファイナライズ中に他のオブジェクトへの参照を使用する唯一の本当の危険は、オブジェクトに適切なインターロックがない限り、ファイナライザーがそれらをクリーンアップしようとしたときに、それらがどのような状態になるかを知る方法がないことです。使用されている可能性もあります。Threading.Interlocked.Exchange を使用して、クリーンアップが進行中であることを示すフラグをテストおよび設定することをお勧めします。

ところで、マイクロソフトがドキュメントで強調していない追加のポイントがいくつかあります。

  1. ファイナライズ可能なオブジェクトが直接的または間接的な参照を保持するオブジェクトはガベージ コレクションの対象外であるため、ファイナライザーを持つオブジェクトは、ファイナライズに必要のないオブジェクトへの参照を保持するべきではありません。
  2. Microsoft の Dispose パターンは、管理されたリソースと管理されていないリソースの両方を持つオブジェクトのクリーンアップを容易にしようとしますが (より適切な用語は、自己クリーニングと非自己クリーニングのほうがよいと思います)、そのようなオブジェクトはほとんどの場合、ファイナライズ中に不要なオブジェクトにリソースを保持します (ルール#1に違反します)。

私見ですが、次の原則を採用することをお勧めします。非自己クリーニング リソースは独自のクラスに配置する必要があります。その唯一の目的は、クリーンアップを処理し、他の場所で使用するためにオブジェクトを公開することです。それらは、ファイナライザーを持つ唯一のクラスでなければなりません。Object から派生したクラスのみがファイナライザーを実装する必要があります。非自己クリーニング リソースを追加する他の派生クラスは、それらのリソースを個別の自己クリーニング クラスにカプセル化し、それらへの参照を保持する必要があります。

于 2010-12-22T16:30:53.363 に答える
1

一般に、オブジェクトにファイナライザーを実装することは望ましくありません。管理対象オブジェクトのリソース クリーンアップを実行する必要がある場合はDispose、Dispose パターンでそれを実行し、適切に実装する必要があります。

最終的にファイナライザーを実装する場合は、アンマネージ リソースにのみアクセスする必要があります。

于 2010-02-24T16:28:37.373 に答える
0

これが懸念される場合は、ファイナライズするよりも破棄する方がよいでしょう。

于 2010-02-24T16:18:28.973 に答える