2

次のシナリオで子ウィンドウをガベージコレクションできるかどうかはわかりません。

  1. ユーザーコントロールには「showpopup」コマンドが含まれています
  2. このコマンドは子ウィンドウを作成し、「Closed」イベントの匿名リスナーを追加します。

public partial class MainPage : UserControl
{
    public ICommand PopupCommand { get; private set; }

    public MainPage()
    {
        InitializeComponent();

        PopupCommand = new DelegateCommand(arg => 
        {
            var child = new ChildWindow();
            child.Closed += (sender, args) =>
            {
                MessageBox.Show("You closed the window!");
            };
            child.Show();
        });
    }
}

PopupCommandのデリゲートにはまだローカルchild変数への参照が含まれているように見えるので、メモリを呼び出すたびにPopupCommandリークメモリが発生しますか?childそれとも、ガベージコレクターは、閉じられた後に破棄できることをどういうわけか認識しますか?


関連:C#およびガベージコレクションのイベントから匿名リスナーを切り離す

4

1 に答える 1

1

次のテストは、いいえ、シナリオでメモリリークが発生しないことを示しています。

public partial class LeakTest : UserControl
{
    public ICommand PopupCommand { get; private set; }

    public LeakTest()
    {
        InitializeComponent();

        PopupCommand = new DelegateCommand(arg =>
        {
            var child = new ChildWindow();
            child.Closed += (sender, args) =>
            {
                System.Diagnostics.Debug.WriteLine("Closed window");
            };

            // when the window has loaded, close it and re-trigger the command
            child.Loaded += (sender, args) =>
            {
                child.Close();
                PopupCommand.Execute(null);
            };
            child.Show();
        });
    }
}

その理由は、Jwostyによってリンクされている(Winforms)投稿への回答で示唆されています:

この例では、パブリッシャーはプライベートメソッドのスコープ内にのみ存在するため、メソッドが戻った後のある時点で、ダイアログとハンドラーの両方がガベージコレクションされます。

言い換えると、メモリリークの懸念は実際には逆です。イベントパブリッシャー(ChildWindowコントロール)はサブスクライバー(DelegateCommand)への参照を保持しますが、その逆はありません。したがって、ChildWindowが閉じられると、ガベージコレクタはそのメモリを解放します。

于 2012-12-22T00:05:42.023 に答える