You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF多窗口图片展示应用内存泄漏引发崩溃问题咨询

WPF窗口内存泄漏修复方案

泄漏根因

  • DispatcherTimer未释放:每个窗口构造函数中声明的DispatcherTimer为局部变量,启动后即使窗口关闭也会持续运行,且Tick事件持有窗口控件、成员变量的强引用,导致GC无法回收窗口实例。
  • ShowDialog资源残留:ShowDialog()打开的模态窗口关闭后不会自动释放所有非托管资源,需要手动清理。
  • 图片资源未释放:从数据库加载的图片流、BitmapImage对象如果未做释放处理,会占用大量非托管内存加剧泄漏。

修复步骤

  1. 把所有窗口的DispatcherTimer从局部变量改为类级成员,重写窗口的OnClosed方法,在方法内停止Timer、注销Tick事件订阅并置空Timer引用。
  2. 使用using包裹ShowDialog()的调用逻辑,窗口关闭后自动释放实例资源。
  3. 从数据库加载图片时,给BitmapImage设置CacheOption = BitmapCacheOption.OnLoad,加载完成后立即释放流资源;窗口关闭时将Image控件的Source置空,不需要复用的图片可调用Freeze()减少内存占用。
  4. 所有事件订阅不要用匿名方法,统一用命名方法,窗口关闭时手动取消所有事件订阅。

修改后代码示例

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 01:06:04