WPF多窗口图片展示应用内存泄漏引发崩溃问题咨询
WPF窗口内存泄漏修复方案
泄漏根因
- DispatcherTimer未释放:每个窗口构造函数中声明的
DispatcherTimer为局部变量,启动后即使窗口关闭也会持续运行,且Tick事件持有窗口控件、成员变量的强引用,导致GC无法回收窗口实例。 - ShowDialog资源残留:
ShowDialog()打开的模态窗口关闭后不会自动释放所有非托管资源,需要手动清理。 - 图片资源未释放:从数据库加载的图片流、BitmapImage对象如果未做释放处理,会占用大量非托管内存加剧泄漏。
修复步骤
- 把所有窗口的
DispatcherTimer从局部变量改为类级成员,重写窗口的OnClosed方法,在方法内停止Timer、注销Tick事件订阅并置空Timer引用。 - 使用
using包裹ShowDialog()的调用逻辑,窗口关闭后自动释放实例资源。 - 从数据库加载图片时,给BitmapImage设置
CacheOption = BitmapCacheOption.OnLoad,加载完成后立即释放流资源;窗口关闭时将Image控件的Source置空,不需要复用的图片可调用Freeze()减少内存占用。 - 所有事件订阅不要用匿名方法,统一用命名方法,窗口关闭时手动取消所有事件订阅。
修改后代码示例
MainWindow
using System; using System.Windows; using System.Windows.Threading; namespace Memory_Leakage { public partial class MainWindow : Window { int d = 0; private DispatcherTimer _activeTimer; public MainWindow() { InitializeComponent(); Dispatcher_timer(); } public void Dispatcher_timer() { _activeTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(60) }; _activeTimer.Tick += ActiveTimer_Tick; _activeTimer.Start(); } private void ActiveTimer_Tick(object sender, EventArgs e) { using(var clock = new Clock()) { clock.ShowDialog(); } } protected override void OnClosed(EventArgs e) { base.OnClosed(e); if (_activeTimer != null) { _activeTimer.Stop(); _activeTimer.Tick -= ActiveTimer_Tick; _activeTimer = null; } } } }
Clock窗口
using System; using System.Windows; using System.Windows.Threading; namespace Memory_Leakage { public partial class Clock : Window { long d = 0; private DispatcherTimer _timer; public Clock() { InitializeComponent(); _timer = new DispatcherTimer(); _timer.Interval = TimeSpan.FromSeconds(1); _timer.Tick += Timer_Tick; _timer.Start(); clocklbl.Content = DateTime.Now.ToLongTimeString().ToUpper(); datelbl.Content = DateTime.UtcNow.ToString("dd-MM-yyyy").ToUpper(); } private void Timer_Tick(object sender, EventArgs e) { clocklbl.Content = DateTime.Now.ToLongTimeString().ToUpper(); if (++d == 20) { using (var imp_Note = new Imp_Note()) { imp_Note.ShowDialog(); } this.Close(); } } protected override void OnClosed(EventArgs e) { base.OnClosed(e); if (_timer != null) { _timer.Stop(); _timer.Tick -= Timer_Tick; _timer = null; } clocklbl = null; datelbl = null; } } }
Imp_Note窗口
using System; using System.Windows; using System.Windows.Threading; namespace Memory_Leakage { public partial class Imp_Note : Window { long d = 0; private DispatcherTimer _timer; public Imp_Note() { InitializeComponent(); _timer = new DispatcherTimer(); _timer.Interval = TimeSpan.FromSeconds(1); _timer.Tick += Timer_Tick; _timer.Start(); } private void Timer_Tick(object sender, EventArgs e) { if (++d == 20) { this.Close(); } } protected override void OnClosed(EventArgs e) { base.OnClosed(e); if (_timer != null) { _timer.Stop(); _timer.Tick -= Timer_Tick; _timer = null; } // 加载了图片的话在此处释放 // 例如:MyImage.Source = null; } } }
验证方法
可使用Visual Studio自带的诊断工具,窗口关闭后拍摄内存快照,搜索对应窗口类名,确认无残留实例即为修复成功。
内容的提问来源于stack exchange,提问作者Muhammad Irfan
相关产品推荐
相关产品推荐

