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变量中删除吗?什么好主意吗?
嗯,我们已经知道委托是不可变的,这就是为什么您使用ref
参数来订阅事件。
现在仔细看看这个方法
public void Close()
{
m_Subscription -= NewEvent;
}
你实际上取消订阅一个副本,而不是从原始委托,这是在MainClass
。换句话说,你只是在子类中重新分配字段,而不是在主类中重新分配字段。