Wpf 使用匿名委托加载/卸载事件时内存泄漏

Wpf 使用匿名委托加载/卸载事件时内存泄漏,wpf,memory-leaks,user-controls,Wpf,Memory Leaks,User Controls,我有一个WPF主窗口,可以在StackPanel中更改(导航)UserControl: // on code behind of MainWindow RootStackPanel.Children.Clear(); UserControl1 uc1= new UserControl1(); uc1.CustomizedEvent1+= EventHandler1; uc1.Customi

我有一个WPF主窗口,可以在StackPanel中更改(导航)UserControl:

// on code behind of MainWindow     
RootStackPanel.Children.Clear();

                UserControl1 uc1= new UserControl1();
                uc1.CustomizedEvent1+= EventHandler1;
                uc1.CustomizedEvent2+= EventHandler2;
                uc1.Loaded += (s, e1) =>
                 {
                        // Do something
                 };

                // Unsubscribe external event to prevent memory leak
                uc1.Unloaded += (s, e1) =>
                    {
                        uc1.CustomizedEvent1 -= EventHandler1;
                        uc1.CustomizedEvent2 -= EventHandler2;
                    };
RootStackPanel.Children.Add(uc1);

// same for UserControl 2,3,4....
应用程序在运行数小时后将崩溃,所以我添加了带有匿名委托的卸载事件处理程序,以通过取消订阅UserControl的所有事件来防止内存泄漏。 使用匿名委托卸载会导致内存泄漏吗?如果是,如何在不调用Unload的情况下取消订阅UserControl的所有事件

我记得内部事件如加载、卸载将由GC处理,对吗

匿名代理何时处理

谢谢大家。

您说过“应用程序在运行数小时后将崩溃,所以我添加了卸载事件”-这是否意味着您经常更改(添加和删除)StackPanel中的UserControld?此外,每次创建新的UserControl时,都会从MainWindow添加这些事件处理程序,对吗


在这种情况下,您做得很好,将一个匿名委托分配给已卸载的事件进行清理是留下良好内存占用的正确方法

我找到了一个简单的解决方案来解决这个问题:

  • 使用和EventHandler方法,而不是匿名委托
  • 在EventHandler方法中调用Unsubscribe

    .....
    // on code behind of MainWindow     
    RootStackPanel.Children.Clear();
    
            UserControl1 uc1= new UserControl1();
            uc1.CustomizedEvent1+= EventHandler1;
            uc1.CustomizedEvent2+= EventHandler2;               
    
            // Unsubscribe external event to prevent memory leak
            //uc1.Unloaded += (s, e1) =>
             //   {
             //       uc1.CustomizedEvent1 -= EventHandler1;
             //       uc1.CustomizedEvent2 -= EventHandler2;
             //   };
    RoutedEventHandler unloadedHandler = null;
    unloadedHandler = delegate(object s, RoutedEventArgs sev)
        {
     uc1.CustomizedEvent1 -= EventHandler1;
             uc1.CustomizedEvent2 -= EventHandler2;
    uc1.Unloaded -= unloadedHandler;
    };
        uc1.Unloaded += unloadedHandler;
    RootStackPanel.Children.Add(uc1);
    // same for UserControl 2,3,4....
    

谢谢您的回复。别忘了标记答案。如果您有任何其他问题,请随时提问。或者打开另一个线程。您说过“应用程序在运行数小时后将崩溃,所以我添加了卸载事件”-这是否意味着您经常更改(添加和删除)StackPanel中的UserControld?**是**而且每次创建新的UserControl时,都会从MainWindow添加这些事件处理程序,对吗?对我想我和你一样,但我不知道卸载事件何时处理/取消订阅?用户报告我的应用程序在工作几个小时后被冻结。那么,我们是否有其他解决方案来取消订阅用户控件的所有事件?当您调用children.Remove(myUserControl)时,会卸载UserControl。如果您不相信我,请在匿名方法中设置断点。:)在您的情况下,匿名方法不持有对其他类的任何引用,因此一旦丢弃完整的UserControl,它将由gc收集。删除(…)我的队友说匿名委托是一种静态方法,只有在关闭主窗口时才能处理。你能确认这个信息吗?CG只有在没有其他对象订阅Unload event.hi@PanagiotisLefas时才会收集用户控件,所以我的解决方案不好,因为Unload的匿名委托仍然保留在MainWindow上,GC无法收集用户控件。你有其他的解决办法吗?Thanks@QuocNguyen您的解决方案很好,您无需取消订阅已卸载的事件。当UserControl从childrens列表中删除时,GC将看到UserControl和匿名事件处理程序都在空间中丢失,它将同时收集这两个。