c# -将事件作为参数传递给子类时发生内存泄漏

本文关键字:子类 泄漏 内存 参数传递 事件 | 更新日期: 2023-09-27 18:04:36

在过去的几天里,我在我们的应用程序中追踪到一个内存泄漏。我知道编写这段代码的开发人员的想法,但我不知道为什么会发生泄漏。我们的想法是有一个类,其中包含一个事件。该类将实例化另一个类,该类将向init方法中的事件添加一个事件处理程序,并调用stop方法将其删除。问题是,事件没有从主类中删除,而InvocationTargetList正在不断增长。下面是一个示例源代码,它显示了这个问题:

public class SampleEventArgs
{
    public SampleEventArgs(string s) { Text = s; }
    public String Text { get; private set; }
}
public class MainClass
{
    public delegate void SampleEventHandler(object sender, SampleEventArgs e);
    public event SampleEventHandler SampleEvent;
    public SubClass m_SubClass = new SubClass();
    public MainClass()
    {
        for (int i = 0; i < 10000; i++)
        {
            m_SubClass.Init(ref SampleEvent);
            m_SubClass.Close();
        }
        if (SampleEvent != null)
            Console.WriteLine("SampleEvent InvocationTargetList length: {0}", SampleEvent.GetInvocationList().Length);
        Console.ReadKey();
    }
}
public class SubClass
{
    public event MemoryLeakTest.MainClass.SampleEventHandler m_Subscription;
    public void Init(ref MainClass.SampleEventHandler SampleEvent)
    {
        SampleEvent += NewEvent;
        m_Subscription = SampleEvent;
    }
    public void Close()
    {
        m_Subscription -= NewEvent;
    }
    public void NewEvent(object sender, SampleEventArgs e)
    {
    }
}

嗯,我已经通过将类传递给Init和Stop方法解决了这个问题,并且还实现了idisposable模式,但我不是100%确定,为什么上面的代码会产生内存泄漏。这是因为将SampleEvent分配给m_Subscription将创建事件的副本,因此事件只会从停止方法中的m_Subscription变量中删除吗?什么好主意吗?

c# -将事件作为参数传递给子类时发生内存泄漏

嗯,我们已经知道委托是不可变的,这就是为什么您使用ref参数来订阅事件。

现在仔细看看这个方法

public void Close()
{
    m_Subscription -= NewEvent;
}

你实际上取消订阅一个副本,而不是从原始委托,这是在MainClass。换句话说,你只是在子类中重新分配字段,而不是在主类中重新分配字段。