UWP中RichEditBox调用LoadFromStream触发System.AccessViolationException
问题描述
我有一个RichEditBox控件,内容从文件加载。极少情况下,调用相关方法时会抛出如下异常:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
相关加载代码:
var RAS = await TXTFile.OpenAsync(FileAccessMode.ReadWrite); RTB.Document.LoadFromStream(TextSetOptions.FormatRtf, RAS);
使用DispatcherTimer连续快速调用该方法可复现此bug,但应用需运行约10至15分钟才会出现。
补充的自动保存相关代码:
private void REB_SelectionChanged(object Sender, RoutedEventArgs EvArgs) { //自动保存 if (AutoSaveSwitch.IsOn == true) { TriggerAutosave(); } } public void TriggerAutosave() { if (DTSave.IsEnabled != true) DTSave.Start(); } private void DTSave_Tick(object sender, object e) { if (AutoSaveSwitch.IsOn == true && TXTFile != null) { try { if (TXTFile != null) { if (AutoSaveSwitch.IsOn == true) { AutosaveWritingToFile(); } else { SaveIndicatorGrid.Visibility = Visibility.Visible; } } else { SaveIndicatorGrid.Visibility = Visibility.Visible; } } catch (Exception EX) { } } else { DTSave.Stop(); } } readonly DispatcherTimer DTSave = new DispatcherTimer(); public MainPage() { InitializeComponent(); DTSave.Interval = new TimeSpan((int)1.5); DTSave.Tick += DTSave_Tick; }
解决方案分析
1. 修复资源泄漏问题
加载文件时未正确释放流资源,并发操作下易引发内存冲突。用using语句确保流自动释放:
using (var RAS = await TXTFile.OpenAsync(FileAccessMode.ReadWrite)) { RTB.Document.LoadFromStream(TextSetOptions.FormatRtf, RAS); }
2. 修正定时器间隔设置
原代码中TimeSpan((int)1.5)是按ticks计算,几乎瞬间触发,会导致高频并发操作。改为设置秒级间隔:
// 设置为1.5秒 DTSave.Interval = TimeSpan.FromSeconds(1.5);
3. 添加并发锁保护共享资源
自动保存和加载操作可能同时访问文件或RichEditBox文档,需加锁避免冲突:
在类中新增锁对象:
private readonly object _fileLock = new object();
修改加载代码:
lock (_fileLock) { using (var RAS = await TXTFile.OpenAsync(FileAccessMode.ReadWrite)) { RTB.Document.LoadFromStream(TextSetOptions.FormatRtf, RAS); } }
修改自动保存方法(假设AutosaveWritingToFile是写文件逻辑):
private void AutosaveWritingToFile() { lock (_fileLock) { // 原有的写文件代码 } }
4. 完善异常处理
原代码捕获异常后直接忽略,不利于排查问题,添加日志记录:
catch (Exception ex) { Debug.WriteLine($"自动保存异常: {ex.Message}\n{ex.StackTrace}"); }
5. 优化定时器启动逻辑
改用IsRunning判断定时器状态,避免重复启动:
public void TriggerAutosave() { if (!DTSave.IsRunning) DTSave.Start(); }
内容的提问来源于stack exchange,提问作者Ivirius
相关产品推荐
相关产品推荐

