9

私はこのコードを持っています

public class Publisher
{
    public event EventHandler SomeEvent;
}

public class Subscriber
{
    public static int Count;

    public Subscriber(Publisher publisher)
    {
        publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
    }

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

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

私が持っている私のアプリケーションのメインメソッドで

static void Main(string[] args)
{
    Publisher publisher = new Publisher();

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

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

    Console.WriteLine(Subscriber.Count.ToString());
}

これを実行すると、出力として 0 が表示されます。コードからイベント サブスクリプションを削除すると、期待どおりの結果 (10) が得られます。

GC.Collect()が呼び出されると、gc は強制的にガベージ コレクションを開始します。Subscriber にはFinalizeが定義されているため、GC はfinalizequeueが空になるまでコレクションを中断します。つまり、すべての Subscription インスタンスがFinalize()メソッドを呼び出した後です (私の仮定が間違っている場合は修正してください)。次の行でGC.WaitForPendingFinalizers()が呼び出され、ファイナライザー キューが空になるまで実行が実質的に中断されます。ここで、出力として 0 があるため、Finalize()が呼び出されていないと考えられます。これにより、GC がサブスクライバー インスタンスを収集するようにマークしなかったため、Finalizer()メソッドが呼び出されていないと考えられます。

だから私は2つの質問があります

  1. 私の仮定は正しいですか? イベント サブスクリプションにより、GC はサブスクライバー インスタンスを収集するようにマークできませんか?
  2. もしそうなら、それはパブリッシャーがサブスクライバーへの参照を保持しているためですか? (ガベージ コレクターとイベント ハンドラー)

私の唯一の推測では、同じパブリッシャー インスタンスを参照している Subscriber のインスタンスが 10 あるため、GC コレクションが発生すると、パブリッシャーへの他の参照があることがわかり、収集できず、結果としてすべてのサブスクリプションがパブリッシャーと一緒にインスタンスが次世代に移動されるため、ガベージ コレクションは発生せず、コード実行がConsole.WriteLine(Subscriber.Count.ToString())に到達した時点でFinalize()が呼び出されません。

私は正しいですか、それともここで何かが欠けていますか?

4

2 に答える 2

3

両方の質問に対する答えはイエスです。

于 2013-06-18T08:57:25.843 に答える