事件订阅导致内存泄漏是因为事件源对订阅者的处理方法持有强引用,使订阅者无法被GC回收;WeakEventManager通过弱引用解决此问题,但高频或需强保证的场景不适用。
为什么事件订阅会导致内存泄漏
在 C# 中,事件本质上是多播委托(MulticastDelegate),当对象 A 订阅对象 B 的事件时,B 会持有一个指向 A 中处理方法的强引用。只要 B 没被释放,A 就无法被 GC 回收——哪怕 A 的业务逻辑早已结束。典型场景如:UI 控件订阅 ViewModel 事件、后台服务订阅长时间存活对象的事件。
这种泄漏不易察觉,尤其在 WPF/WinForms 中反复创建/销毁视图时,内存占用持续上涨却无明显异常。
WeakEventManager 是最稳妥的内置方案
WeakEventManager 是 WPF 提供的、专为解决 UI 层事件内存泄漏设计的弱事件管理器。它不持有事件处理者的强引用,允许处理者被 GC 正常回收。
使用要点:
- 必须继承
WeakEventManager并实现StartListening/StopListening - 事件源(sender)需支持
INotifyPropertyChanged或自定义事件(如PropertyChanged、CollectionChanged) - 推荐用泛型静态类封装,避免重复注册:例如
PropertyChangedEventManager.AddHandler - WPF 之外(如 .NET Core Console 或 Blazor)默认不可用,需手动引入
PresentationCore引用
示例(监听 INotifyPropertyChanged):
PropertyChangedEventManager.AddHandler(source, handler, "PropertyName");
触发后若 handler 所属对象已回收,该监听自动失效,不会 crash。