7

IDisposable を実装するメンバー (obj) を持つ単純なクラス MyDataClass があります。

public class MyDataClass : IDisposable
{
    private DisposableObject obj;
    private List<string> list;
    private int c;

    public MyDataClass()
    {
        obj = new DisposableObject();
        list = new List<string>();
        c = 114;
    }

    public void Dispose()
    {
        obj.Dispose();
    }
}

public class DisposableObject : IDisposable
{
    public void Dispose()
    {
        // Free resource
        Console.WriteLine("Dispose DisposableObject");
    }
}

コード分​​析を実行すると、 MyDataClass実装のDispose()メソッドでGC.SuppressFinalize()メソッドを呼び出す必要があることを示す CA1063 警告が表示されます。

そして、私はこの CA1063 警告について本当に混乱しています。私の知る限り、GC.SuppressFinalize()を呼び出してガベージ コレクターに通知する必要があるためです。

「ヘイ GC、このオブジェクトについては心配しないでください。私はすでにすべてのクリーニング作業を行っているからです!」

だから、私が間違っているかどうかを確認してください。GC.SuppressFinalize()を追加すると、CA1063 は削除されますが、GC でオブジェクトがクリーンアップされません。したがって、他のクラス メンバー (マネージ コード) が消去されないため、メモリ リークが発生します。

4

3 に答える 3

5

回答を受け入れたにもかかわらず、あなたはまだ混乱しているように感じます。説明させてください:

ガベージ コレクター (GC) には、到達できないオブジェクトをメモリから削除するという厄介なタスクがあります。

到達可能性

オブジェクトAは、任意の GCルートからオブジェクトへの参照のチェーンがある場合にのみ到達可能です。ルートの例は、スタックや静的フィールドです。したがって、Aが到達可能かどうかを判断するために、GC が行う必要があるのは、 object を参照する参照を持つオブジェクトを参照するスタック上の参照を見つけることだけですA。そのようなチェーンが見つからない場合、オブジェクトAには到達できません。1

そのため、GC は にA到達できないと判断すると、それをメモリから削除する必要があります。ただし、それを行う前に、GC は、実行する必要がAあるファイナライザー ( ) があるかどうかを確認します。~Aそうでない場合は、メモリから削除Aされ、GC が処理されます。

ファイナライズ

ただし、A実行する必要があるファイナライザーがある場合、ファイナライザーが終了する前にオブジェクトをメモリから削除することはできません。そのため、ファイナライザー キューAへの参照を追加し、(まだ) メモリからオブジェクトを削除しません。これで、ガベージ コレクターは今のところ完了です。ただし、GC が再度実行されると、到達可能かどうかを再度判断しようとします。さいわい、ファイナライザ キューはガベージ コレクタのルートの 1 つでもあるため、ファイナライザ キューから への参照があると判断され、到達可能になり、再びメモリから削除されることはありません。AAAA

これに伴い、ファイナライザー キューにオブジェクトがあるかどうかを定期的にチェックするスレッドであるファイナライザー スレッドが登場します。存在する場合は、1 つを選択し、そのファイナライザー メソッドを実行します。最終的に、ファイナライザ スレッドは のファイナライザを実行しますA。これが完了すると、への参照がAファイナライザ キューから削除されます。

掃除

その後、しばらくして、ガベージ コレクターが再び実行され、A到達可能かどうかを再度判断しようとします。どこからも参照されていないため、ファイナライザー キューからでもA到達できません。GCAがメモリから削除されます。


ご覧のとおり、通常、GC は到達不能なオブジェクトを検出したのと同じ収集サイクルで削除できますが、実行する必要のあるファイナライザーがオブジェクトにある場合、オブジェクトが収集されるまでに複数のサイクルが必要になる場合があります。したがって、CA1063 では、メモリから削除する前にオブジェクトをファイナライズする必要がないことを GC に知らせるメソッドを配置GC.SuppressFinalize()することをお勧めします。Disposeそのため、オブジェクトは常に最終的にメモリから削除されます。

ファイナライザーがない場合は、追加する必要がないことに注意してください。そのGC.SuppressFinalize()ため、その点で CA1063 警告は少し余分です。

ガベージ コレクターの詳細については、この MSDN 記事 を参照してください


1 )到達可能性は、参照を破棄した後に参照を設定することが一般的である理由nullです。これにより、参照されたオブジェクトが到達不能になる可能性が高くなるため、削除の候補になります。

2 )ファイナライザーを使用して、別の到達可能なオブジェクトまたはルート (静的フィールドなど) からの参照を追加することにより、復活させることができます (ただし、お勧めしません)。これにより、再び到達可能になり、ガベージ コレクターはそれを削除しません。ただし、そのファイナライザーは既に一度呼び出されているため、再度実行されることはありません。 AAA

于 2012-08-03T14:24:33.860 に答える
5

このメソッドは、ファイナライザーGC.SuppressFinalize()を実行しないように VM に指示します。これは、C# で面白い方法です。

~MyDataClass()

警告を削除するには、クラスを封印するか、完全なIDisposable パターンを実装する必要があります。

于 2012-08-03T09:48:25.530 に答える
3

を追加するGC.SuppressFinalize()と、CA1063 は削除されますが、GC でオブジェクトがクリーンアップされません。

いいえ、オブジェクトは引き続き収集されます。

「ヘイ GC、このオブジェクトについては心配しないでください。私はすでにすべてのクリーニング作業を行っているからです!」

あなたは実際に言っているだけです: このオブジェクトのファイナライザー (デストラクタ) について心配する必要はありません。それがあれば。

コード分​​析が間違っているところです。クラスにはIDisposable.Dispose()メソッドがありますが、デストラクタはありません。したがって、警告は無意味であり、過保護であり、間違った理由でトリガーされます。無効にするか、無視してください。

于 2012-08-03T09:41:35.500 に答える