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

WinUI 3桌面应用中无法捕获的Access violation错误排查求助

WinUI 3桌面应用Access Violation崩溃排查问题

环境与症状

  • WinUI 3 v1.2,.NET 7,x64 Debug模式
  • 仅特定操作序列后崩溃,Visual Studio Output窗口显示:

程序'[28716] xxxxxxx.exe'已退出,代码为3221225477 (0xc0000005) 'Access violation'。

  • 已注册的全局异常处理器均未触发:
UnhandledException += App_UnhandledException;
System.AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Microsoft.UI.Xaml.Application.Current.UnhandledException += Current_UnhandledException;

窗口相关逻辑

次级窗口启动代码

if (App.ShellPage.SettingsStatusWindow)
{
    StatusWindow = new StatusWindow();                               // create new window
    StatusWindow.Activate();
}
else
{
    WeakReferenceMessenger.Default.Send(new CloseWindowMessage());   // close windows
}

消息触发窗口关闭

WeakReferenceMessenger.Default.Register<CloseWindowMessage>(this, (r, m) =>
{
    WeakReferenceMessenger.Default.Unregister<TraceMessage>(this);
    WeakReferenceMessenger.Default.Unregister<CloseWindowMessage>(this);
    Close();
});

标题栏Close按钮触发关闭

private void StatusWindow_Closed(object sender, WindowEventArgs args)
{
    Closed -= StatusWindow_Closed;
    WeakReferenceMessenger.Default.UnregisterAll(this);
    WeakReferenceMessenger.Default.Send(new WindowClosedMessage());
}

注:使用CommunityToolkit.Mvvm的WeakReferenceMessenger

异常现象差异

  • 通过CloseWindowMessage关闭窗口后,约1秒内触发Access Violation
  • 点击标题栏Close按钮关闭窗口后,后续操作无异常
  • 尝试搭建小型复现应用,无法触发该错误

排查方案

1. 启用本机代码调试捕获崩溃

在项目属性的调试选项卡中,勾选「启用本机代码调试」。这样Access Violation发生时会直接触发调试中断,可查看完整的托管+本机调用栈,定位到具体的内存访问违规位置。

2. 追踪消息流向与生命周期

在消息发送、注册、注销的关键节点添加Debug日志,确认消息处理的时机是否正确:

// 发送CloseWindowMessage时记录接收者数量
Debug.WriteLine($"Sending CloseWindowMessage, recipients count: {WeakReferenceMessenger.Default.GetRegisteredRecipients<CloseWindowMessage>().Count()}");
WeakReferenceMessenger.Default.Send(new CloseWindowMessage());

// StatusWindow注销时记录实例哈希
Debug.WriteLine($"Unregistering StatusWindow {this.GetHashCode()}");
WeakReferenceMessenger.Default.UnregisterAll(this);

同时给StatusWindow添加析构函数,确认对象是否被正确回收:

~StatusWindow()
{
    Debug.WriteLine($"StatusWindow {this.GetHashCode()} finalized");
}

3. 统一窗口关闭后的消息注销逻辑

当前两种关闭方式的注销逻辑不一致:消息触发时仅注销特定消息,标题栏关闭时注销所有消息。建议统一逻辑,先关闭窗口再注销消息,避免窗口关闭过程中还有消息触发:

WeakReferenceMessenger.Default.Register<CloseWindowMessage>(this, (r, m) =>
{
    Close();
    // 窗口关闭完成后再统一注销所有消息
    WeakReferenceMessenger.Default.UnregisterAll(this);
});

4. 生成并分析崩溃转储

在Visual Studio的「调试→选项→调试→转储文件」中,开启「自动创建转储文件」,设置转储类型为「完整」。应用崩溃后生成的.dmp文件可直接在Visual Studio中打开,分析调用栈、内存对象,定位违规的内存引用。

5. 检查窗口实例的强引用

排查是否有其他模块持有StatusWindow的强引用,导致窗口关闭后无法被GC回收,进而引发后续的消息访问问题。可使用Visual Studio的内存诊断工具(调试→性能探查器→内存使用),在窗口关闭后拍摄内存快照,搜索StatusWindow实例是否仍存在。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 09:20:42