WPF关闭窗口后定时器未停止、内存占用未降低问题咨询
问题根源
1. 内存无法释放的原因
MoviePosters类中定义的watchingMovie类型变量MW是静态变量,静态变量的生命周期和整个应用程序进程一致,只要你每次打开新的watchingMovie窗口时给MW赋值,旧的watchingMovie实例就会一直被这个静态变量持有强引用,哪怕你调用了Close()方法关闭窗口,GC也无法回收这部分实例占用的内存,所以每打开一次窗口内存就会持续上涨。
2. 窗口关闭后定时器仍运行的原因
有两个原因共同导致这个问题:
- 你的清理逻辑只写在了自定义的
Exit_Click点击事件中,如果用户通过点击窗口右上角的关闭按钮、Alt+F4等其他方式关闭窗口,这个事件不会触发,定时器也就不会被停止。 DispatcherTimer的执行依赖当前应用程序的UI线程调度队列,只要定时器没有被显式停止、Tick事件绑定没有被解除,哪怕对应的窗口已经关闭,只要UI线程还在运行,Tick事件就会持续被触发。- 额外注意:你当前
Exit_Click方法内的执行顺序有误,先调用了GC回收,之后才停止定时器,执行GC的时候定时器仍处于运行状态,实例还被事件引用,自然不会被回收。
修复方案
- 移除静态变量引用
删除MoviePosters类中的static watchingMovie MW;定义,如果确实需要持有当前打开的播放窗口引用,改为使用普通实例变量,并且在窗口关闭后置为null。
修改后的MoviePosters代码示例:
namespace WpfApplication49 { public partial class MoviePosters : Window { // 去掉static修饰符 private watchingMovie MW; private void myControl1_Click(object sender, myClickEventArgs e) { // 如果要限制同时只打开一个播放窗口,先判断已有实例是否存在,存在就先关闭 if (MW != null) { MW.Close(); } MW = new watchingMovie((string)e.my.Tag.ToString()); // 订阅播放窗口的关闭事件,关闭后清空引用 MW.Closed += (s, args) => MW = null; MW.Show(); } } }
- 统一窗口关闭清理逻辑
不要把清理逻辑只放在按钮点击事件中,重写watchingMovie窗口的OnClosed方法,确保无论以什么方式关闭窗口,都会执行清理操作,同时修正执行顺序:
namespace WpfApplication49 { public partial class watchingMovie : Window { public readonly DispatcherTimer timer = new DispatcherTimer(); public watchingMovie(String movie) { InitializeComponent(); passedMovie = movie; timer.Interval = TimeSpan.FromMilliseconds(200); timer.Tick += timer_Tick; this.Topmost = true; } // 重写关闭方法,统一处理清理逻辑 protected override void OnClosed(EventArgs e) { // 先清理定时器 if (timer != null) { timer.Stop(); timer.Tick -= timer_Tick; } // 清理媒体播放器资源 if (ME != null) { ME.Stop(); ME.Close(); ME.Source = null; } base.OnClosed(e); } public void Exit_Click(object sender, RoutedEventArgs e) { // 直接调用Close即可,所有清理逻辑都在OnClosed里统一处理 this.Close(); } // 其余原有代码保持不变 void timer_Tick(object sender, EventArgs e) { // 原有逻辑不变 } } }
- 删除手动GC调用
不需要手动调用GC.Collect()等方法,只要所有强引用都被正确释放,GC会自动在合适的时机回收内存,手动调用GC不仅会降低程序性能,也无法解决因为强引用未释放导致的内存泄漏问题。
按照上面的方案修改后,关闭watchingMovie窗口时所有资源都会被正确释放,内存会回落至打开播放窗口前的水平,定时器也不会再继续运行。
内容的提问来源于stack exchange,提问作者StealthRT
相关产品推荐
相关产品推荐

