EventHandler内存泄漏

时间:2015-11-19 07:30:30

标签: c# events

我有ObservableCollection,它包含Item,每个Item都包含事件MessageEvent,在其上订阅一些匿名方法。主要问题是为什么在Items.Clear();匿名之后还活着?

的Xaml:

<Grid>
    <Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>

代码:

namespace WpfApplication207
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    Data D = new Data();
    public MainWindow()
    {
        InitializeComponent();
        DataContext = D;

    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        D.CleanCollection();
    }
}

public class Item
{
    public int id { get; set; }

    public delegate void SendMessage (int i);

    public event SendMessage MessageEvent;

    public Item()
    {
        MessageEvent += (o) => { Console.WriteLine("Bad thing happens"); };
        UpdateAsync();
    }

    public void UpdateAsync()
    {
        Action Test = new Action(DoSomeWork);
        IAsyncResult result = Test.BeginInvoke(null,null);
    }

    public void DoSomeWork()
    {
        while(true)
        {
            System.Threading.Thread.Sleep(3000);
            if (MessageEvent!=null)
            {
                MessageEvent(1);
            }
        }
    }
}
public class Data
{
    public ObservableCollection<Item> Items { get; set; }
    public Data()
    {
        Items = new ObservableCollection<Item>();
        Items.Add(new Item { id = 1});
    }

    public void CleanCollection()
    {
        Items.Clear();
    }
}

1 个答案:

答案 0 :(得分:2)

  

主要问题是为什么Items.Clear();匿名之后还活着?

因为使用items.Clear()并不意味着项目会被垃圾收集。它只表示ObservableCollection<T>不再拥有对这些项的引用,如果他是唯一一个这样的项,那么只有在下一个GC中才会收集这些项,其中下一个GC时间是任意的时间由运行时确定。

如果您希望项目停止打​​印这些消息,您可以做两件事:

  1. 将代理作为Item
  2. 中的字段
  3. 一旦不再需要使用的物品,请使用一次性图案取消注册:

    public class Item : IDisposable
    {
        public int id { get; set; }
    
        private Action action;
        public event SendMessage MessageEvent;
    
        public Item()
        {
            action = () => Console.WriteLine("Bad thing happens");
            MessageEvent += action;
            UpdateAsync();
        }
    
        public void Dispose()
        {
            Dispose(true);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (!disposing)
                return;
    
            MessageEvent -= action;
        }
    }
    
    public class Data
    {
        public ObservableCollection<Item> Items { get; set; }
        public Data()
        {
            Items = new ObservableCollection<Item>();
            Items.Add(new Item { id = 1});
        }
    
        public void CleanCollection()
        {
            foreach (var item in Items)
            {
                item.Dispose();
            }
    
            items.Clear();
        }
    }