私はこのコードを持っています
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つの質問があります
- 私の仮定は正しいですか? イベント サブスクリプションにより、GC はサブスクライバー インスタンスを収集するようにマークできませんか?
- もしそうなら、それはパブリッシャーがサブスクライバーへの参照を保持しているためですか? (ガベージ コレクターとイベント ハンドラー)
私の唯一の推測では、同じパブリッシャー インスタンスを参照している Subscriber のインスタンスが 10 あるため、GC コレクションが発生すると、パブリッシャーへの他の参照があることがわかり、収集できず、結果としてすべてのサブスクリプションがパブリッシャーと一緒にインスタンスが次世代に移動されるため、ガベージ コレクションは発生せず、コード実行がConsole.WriteLine(Subscriber.Count.ToString())に到達した時点でFinalize()が呼び出されません。
私は正しいですか、それともここで何かが欠けていますか?