4

私はグーグルで検索しましたが、欲しいものが得られませんでした。私は正しいか間違っているかわかりません。見て、私は GC.Collect() を理解しようとしているので、ここにコードがあります..

public class SomePublisher
{
    public event EventHandler SomeEvent;
}

public class SomeSubscriber
{
    public static int Count;

    public SomeSubscriber(SomePublisher publisher)
    {
        publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
    }

    ~SomeSubscriber()
    {
        SomeSubscriber.Count++;
    }

    private void publisher_SomeEvent(object sender, EventArgs e)
    {
        // TODO: something
    }
}

私はメインスレッドでこれを行います..

 SomePublisher publisher = new SomePublisher();

        for (int i = 0; i < 10; i++)
        {
            SomeSubscriber subscriber = new SomeSubscriber(publisher);
            subscriber = null;
        }

        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine(SomeSubscriber.Count.ToString());
        Console.ReadLine();

私は出力0を取得していますが、GC.Collect()はメモリからclass1オブジェクトを削除する必要があるため、class1デストラクタを呼び出す必要があるため、カウントを10に増やす必要があるため、私によれば10になるはずです..

4

2 に答える 2

8

(C# にはデストラクタ1がなく、ファイナライザがあることにも注意してください。これらは非常に異なるものであり、混同しないでください。)

「問題」は次の行にあります。

publisher.SomeEvent += new EventHandler(publisher_SomeEvent);

これによりpublisher_SomeEvent()、特定のオブジェクト インスタンスのメソッドを対象とするデリゲートが作成され、このデリゲートがイベントの呼び出しリストに追加されますpublisher.SomeEvent。このデリゲート オブジェクトはターゲット オブジェクトを参照しているため、オブジェクトの収集が妨げられています。(これは良いことです。特定のオブジェクトのメソッドにデリゲートを取得する場合、デリゲートが参照されなくなるまで、そのオブジェクトを収集したくありません。)

これは技術的にはまったく問題ではありませんが、まだ参照されているオブジェクトを存続させ続けるランタイムです。

説明のために、これは一連の参照です。

SomePublisher -+-> EventHandler --> SomeSubscriber
               |
               +-> EventHandler --> SomeSubscriber
               |
               +-> (Eight more...)

を呼び出す前に、次の 2 つのいずれかを行う必要がありますGC.Collect()

  1. SomePublisher各オブジェクトをリリースする前に、イベントからサブスクライブを解除してください。これにより、EventHandlerデリゲート インスタンスとSomeSubscriberそれらが参照するインスタンスの両方がコレクションの対象になります。
  2. 設定しpublisher = null;ます。これにより、オブジェクト グラフ全体がコレクションの対象になります。

どちらの場合も、これによりオブジェクトへのすべての参照が解放されSomeSubscriberます。


1 C# の仕様ではこれらのコード ブロックを「デストラクタ」と呼んでいますが、これは恐ろしい名前です。「ファイナライザー」は、オブジェクトに到達できなくなったときにガベージ コレクターによって呼び出されるコードを表す一般的な用語であるため、ガベージ コレクション言語に精通している人は混乱するでしょう。特に C++ 開発者は、デストラクタが別のタイミングで実行されることを期待します。はい、C# には「デストラクタ」と呼ばれるものがありますが、デストラクタではありません。(言ってもそうはなりません!)

于 2013-08-13T07:20:59.690 に答える