为什么用空lambda函数注册事件会导致内存中的强引用
本文关键字:内存 引用 lambda 函数 事件 注册 为什么 | 更新日期: 2023-09-27 18:12:08
有一些示例代码:
public class Publisher
event Published()
end class
public class Subscriber
public sub new(Publisher as Publisher)
addhandler Publisher.Published,
sub()
end sub
end sub
end class
注册到
Subscriber
构造器中的Publisher
事件是否阻止Subscriber
被垃圾收集,即使一个空lambda函数,不捕获Subscriber
,作为事件处理程序传递?在c#中是一样的吗?
编辑
一个简单的控制台应用程序来测试它:Sub Main()
Dim Publisher As New Publisher
For i = 1 To 1000000
Dim Subscriber As New Subscriber(Publisher)
Next
GC.Collect()
Dim TotalMemory = GC.GetTotalMemory(True)
Trace.WriteLine(TotalMemory)
End Sub
不幸的是,应用程序在垃圾收集之后消耗了36mb的内存,这意味着所有订户都留在内存中!在不同的目标框架2.0、3.0、3.5、4.0、4.5上调试和发布,得到相同的结果。
- 任何人都可以重现问题或解释为什么添加事件处理程序的方式?
如果您在匿名函数中没有引用任何与订阅者相关的内容,那么它将被编译为订阅者类的静态方法,因此它不会阻止订阅者类的任何实例被垃圾收集。你可能想看看这个链接- http://blogs.msdn.com/b/oldnewthing/archive/2006/08/02/686456.aspx -了解更多信息。
更新。下面的代码显示了在发布模式下运行时几乎相同的总内存值(在调试模式下,它确实像你说的那样工作):
internal class Program {
private static void Main(string[] args) {
Console.WriteLine("Before: {0}", GC.GetTotalMemory(true));
var pub = new Publisher();
for (int i = 0; i < 1000000; i++) {
var sub = new Subscriber(pub);
}
GC.Collect();
Console.WriteLine("After: {0}", GC.GetTotalMemory(true));
Console.ReadKey();
}
}
public class Publisher {
public EventHandler Published;
}
public class Subscriber {
public Subscriber(Publisher pub) {
pub.Published += delegate { };
}
}