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

WPF视图模型未释放引发内存泄漏,如何解决Dispatcher相关问题?

WPF ViewModel内存泄漏解决:Dispatcher Lambda捕获this问题

问题根源

你的代码中,Dispatcher.CurrentDispatcher.Invoke的匿名Lambda捕获了ViewModel的强引用this。如果这个Lambda被Dispatcher队列持有(比如调用线程是Timer后台线程,Dispatcher需要排队执行委托),ViewModel会因为这个强引用无法被GC回收,最终导致内存泄漏。

解决方案

1. 使用弱引用(WeakReference)避免强引用捕获

通过创建ViewModel的弱引用,让Lambda只持有弱引用,不会阻止GC回收ViewModel。当ViewModel已被释放时,跳过更新操作:

public async Task RefreshAsync2(CancellationToken token = default)
{
    var data = await Mediator.Send(new GetDataQuery());
    if (data == null) return;

    // 持有ViewModel的弱引用,替代直接捕获this
    var weakViewModel = new WeakReference<YourViewModelType>(this);
    Dispatcher.CurrentDispatcher.Invoke(() => {
        if (weakViewModel.TryGetTarget(out var viewModel))
        {
            viewModel.ViewModelInfo = data;
        }
    });
}

2. 从源头切断无效调用(结合IDisposable)

如果RefreshAsync2是由Timer等定时任务触发,在ViewModel销毁时停止定时任务,避免后续的Dispatcher调用:

public class YourViewModelType : INotifyPropertyChanged, IDisposable
{
    private Timer _refreshTimer;

    public YourViewModelType()
    {
        // 初始化定时触发的Timer
        _refreshTimer = new Timer(_ => RefreshAsync2().ConfigureAwait(false), 
                                 null, 
                                 TimeSpan.Zero, 
                                 TimeSpan.FromMinutes(1));
    }

    public void Dispose()
    {
        // 销毁时停止Timer,避免后续调用RefreshAsync2
        _refreshTimer?.Dispose();
        _refreshTimer = null;
    }

    // 你的RefreshAsync2方法...
}

3. 优化线程上下文判断(减少Dispatcher调用)

先检查当前线程是否拥有Dispatcher访问权限,如果是则直接更新字段,否则再用弱引用+Dispatcher:

public async Task RefreshAsync2(CancellationToken token = default)
{
    var data = await Mediator.Send(new GetDataQuery());
    if (data == null) return;

    if (Dispatcher.CurrentDispatcher.CheckAccess())
    {
        // 当前在UI线程,直接更新
        ViewModelInfo = data;
    }
    else
    {
        var weakViewModel = new WeakReference<YourViewModelType>(this);
        Dispatcher.CurrentDispatcher.Invoke(() => {
            if (weakViewModel.TryGetTarget(out var viewModel))
            {
                viewModel.ViewModelInfo = data;
            }
        });
    }
}

补充说明

  • 弱引用的核心是:只有当ViewModel还存活时,才执行更新操作,既解决了内存泄漏,也避免了对已释放对象的无效操作。
  • 实现IDisposable是后台任务场景下的常规操作,能从源头减少无效的异步调用,和弱引用配合使用效果最佳。

内容的提问来源于stack exchange,提问作者Luka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:00:15