繁体   English   中英

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

[英]C# - Memory leak when passing an event as parameter to a subclass

在过去的几天里,我一直跟踪应用程序中的内存泄漏。 我知道编写此代码的开发人员的想法,但是我并不是真的知道为什么会发生泄漏。 想法是要有一个包含事件的类。 该类将实例化另一个类,该类将在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方法来解决此问题,并且还实现了IDisposeable模式,但我不确定100%为什么上面的代码会导致内存泄漏。 造成这种情况的原因是,因为将SampleEvent分配给m_Suscription会创建该事件的副本,因此该事件将仅从Stop方法中的m_Subscription变量中删除? 有任何想法吗?

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

现在仔细看一下这个方法

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

实际上,您是从副本退订,而不是MainClass原始委托MainClass 换句话说,您将只重新分配子类中的字段,而不是重新分配主类中的字段。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM