更新问题排查文档

This commit is contained in:
zhengxuan.zhang
2026-08-04 10:26:40 +08:00
parent f2ca9cb611
commit 1217519b54
+41 -25
View File
@@ -2,7 +2,7 @@
> 审计日期:2026-08-03
> 审计范围:硬件事件、`AppStateService`、调试面板、探测器帧队列、BGA 向导及窗口生命周期。
> 本文用于记录代码审阅结论,不代表问题已经修复
> 本文最初用于记录代码审阅结论2026-08-04 更新:第一、二阶段(P0-1、P0-2、P1-1、P1-2)已修复并通过编译验证,其余问题仍待处理,详见第 4、5 节
## 1. 审计结论
@@ -12,10 +12,10 @@
| 编号 | 问题 | 当前判断 | 证据 |
|---|---|---|---|
| P0-1 | BGA 检测方法存在无条件 `return`,流水线结果缺失时静默退出 | **确认存在** | [`InspectionTaskWizardViewModel.cs:638`](../../XplorePlane/ViewModels/Inspection/TaskWizard/InspectionTaskWizardViewModel.cs#L638);后续代码已被编译器报 `CS0162` |
| P0-2 | `MotionState` 事件可能无变化洪泛 | **确认存在** | `BuildMotionStateSnapshot` 每次生成新的 record[`AppStateService.cs:790-794`](../../XplorePlane/Services/AppState/AppStateService.cs#L790) 使用 `ReferenceEquals` 去重 |
| P1-1 | `_acquireQueue` 长期保留大尺寸帧 | **确认存在,需先验证运行时占用** | [`DetectorFramePipelineService.cs:29`](../../XplorePlane/Services/Main/Viewport/DetectorFramePipelineService.cs#L29) 入队后没有对应出队;处理队列 `_processQueue` 则有后台消费者,不应把两者混为一谈 |
| P1-2 | 调试面板 `PerformanceMonitorViewModel` 事件订阅无法解除 | **确认存在** | [`PerformanceMonitorViewModel.cs:84-90`](../../XplorePlane/ViewModels/Debug/PerformanceMonitorViewModel.cs#L84) 使用匿名 lambda[`Dispose`](../../XplorePlane/ViewModels/Debug/PerformanceMonitorViewModel.cs#L96) 未反订阅 |
| P0-1 | BGA 检测方法存在无条件 `return`,流水线结果缺失时静默退出 | **已修复**2026-08-04 | 删除 [`InspectionTaskWizardViewModel.cs`](../../XplorePlane/ViewModels/Inspection/TaskWizard/InspectionTaskWizardViewModel.cs) 中的无条件 `return`,流水线复用失败时回退到真实检测路径(原有仿真数据兜底不变);`CS0162` 不可达代码警告已消除 |
| P0-2 | `MotionState` 事件可能无变化洪泛 | **已修复**2026-08-04 | [`AppStateService.cs:790-795`](../../XplorePlane/Services/AppState/AppStateService.cs#L790) `SetMotionState` 去重改为值比较(`old == newState`record 自动生成 `Equals`),设备静止时不再无条件触发 UI 更新 |
| P1-1 | `_acquireQueue` 长期保留大尺寸帧 | **已修复**2026-08-04 | [`DetectorFramePipelineService.cs`](../../XplorePlane/Services/Main/Viewport/DetectorFramePipelineService.cs) 移除 `_acquireQueue`,改为原子饱和计数器,不再持有约 37MB/帧的图像对象;`AcquireQueueCount`/`AcquireQueueCapacity` 对外行为不变,property 测试无需改动 |
| P1-2 | 调试面板 `PerformanceMonitorViewModel` 事件订阅无法解除 | **已修复**2026-08-04 | [`PerformanceMonitorViewModel.cs`](../../XplorePlane/ViewModels/Debug/PerformanceMonitorViewModel.cs) 匿名 lambda 改为具名事件处理器,`Dispose` 中完整反订阅 7 个 AppState 事件 |
| P1-3 | `_latestGeometry` 跨线程读写缺少明确同步 | **确认存在,风险待量化** | [`AppStateService.cs:161`](../../XplorePlane/Services/AppState/AppStateService.cs#L161)、[`AppStateService.cs:566-571`](../../XplorePlane/Services/AppState/AppStateService.cs#L566) |
| P1-4 | 探测器断连状态判断不是单一原子事务 | **部分确认** | [`AppStateService.cs:579-585`](../../XplorePlane/Services/AppState/AppStateService.cs#L579) 在后台线程读取 `_detectorState`;最终状态更新仍通过原子替换,但 `wasConnected` 与后续更新之间可能交错 |
| P1-5 | `CncExecutionStateChanged` 没有主项目订阅方 | **确认存在** | `AppStateService` 有发布事件,但当前主项目未发现 `+=` 订阅;部分界面改读 `MainViewportService.IsCncRunning`,形成双来源风险 |
@@ -29,34 +29,34 @@
## 2. 审阅材料中的修正项
### 2.1 “`_acquireQueue` 和 `ProcessFrameDequeued` 都没有消费者”不准确
### 2.1 “`_acquireQueue` 和 `ProcessFrameDequeued` 都没有消费者”不准确`_acquireQueue` 已于 2026-08-04 移除)
实现中:
实现中:
- `_acquireQueue` 确实只有入队和容量淘汰,没有业务消费方;这是需要处理的资源保留问题。
- `_processQueue``ProcessLoopAsync` 消费,并发布 `ProcessFrameDequeued`;因此处理队列本身不是“只写不读”。
- `_acquireQueue` 确实只有入队和容量淘汰,没有业务消费方;这是需要处理的资源保留问题。已修复:改为原子饱和计数器,不再持有帧对象。
- `_processQueue``ProcessLoopAsync` 消费,并发布 `ProcessFrameDequeued`;因此处理队列本身不是“只写不读”,未改动
- `ProcessFrameDequeued` 当前没有主项目订阅方,但它仍由处理线程发布,不能据此推断 `_processQueue` 未消费。
### 2.2 “错误事件完全没有订阅方”需要限定范围
射线源的 `ErrorOccurredEvent` 在模块自身已有 ViewModel 订阅,用于局部显示;更准确的问题是:主项目没有把运动、探测器和射线源故障统一映射到 `SystemState`,因此主界面和权限逻辑无法依赖统一故障状态。
### 2.3 “内存恒定约 600 MB”应改为容量上界风险
### 2.3 “内存恒定约 600 MB”应改为容量上界风险(已通过移除 `_acquireQueue` 解决)
在 3072×3060、16 位图像下,单帧原始数组约 18.8 MB,BitmapSource 也可能占用相近量级。由于 `_acquireQueue` 容量为 16,静态上界确实可能达到数百 MB;但实际占用还受 BitmapSource 内存布局、淘汰时机和 GC 影响,应通过运行时计数器确认后再作为验收数字
在 3072×3060、16 位图像下,单帧原始数组约 18.8 MB,BitmapSource 也可能占用相近量级。由于 `_acquireQueue` 容量为 16,静态上界确实可能达到数百 MB。2026-08-04 已移除该队列对帧对象的持有,改为纯计数,不再引入这部分常驻内存;P2-5 中提到的“每帧复制大数组”仍存在(用于生成 `previewImage`),但不再叠加队列滞留
## 3. 建议修复顺序
### 第一阶段:解除当前功能阻塞
### 第一阶段:解除当前功能阻塞 —— 已完成(2026-08-04
1. 处理 `ExecuteRunBgaDetection` 的流水线结果缺失分支:明确显示错误并允许回退到受控的真实检测路径;删除无条件死代码 `return`,不要静默结束。
2. 为 BGA 流水线缺失输出增加测试,覆盖“成功复用、缺失输出、输出类型错误”三种情况。
1. ~~处理 `ExecuteRunBgaDetection` 的流水线结果缺失分支:明确显示错误并允许回退到受控的真实检测路径;删除无条件死代码 `return`,不要静默结束。~~ 已删除 `return`,回退到真实检测路径。
2. 为 BGA 流水线缺失输出增加测试,覆盖“成功复用、缺失输出、输出类型错误”三种情况。**未完成**,本次未新增测试(`XplorePlane.Tests` 当前存在与本次改动无关的历史编译错误,阻塞了单测执行,详见第 4 节说明及第 5 节遗留事项)。
### 第二阶段:降低事件与内存压力
### 第二阶段:降低事件与内存压力 —— 已完成(2026-08-04
1.`MotionState` 去重从引用比较改为值比较,或在状态未变化时不创建新 record;同时增加事件频率测试。
2. 明确 `_acquireQueue` 的职责:如果只是调试缓存,改为有限的轻量元数据/可配置采样;如果需要消费,则补齐消费者和释放策略。
3.`PerformanceMonitorViewModel` 的匿名订阅改为具名处理器或保存 `SubscriptionToken`,在 `Dispose` 中完整解除订阅。
1. ~~将 `MotionState` 去重从引用比较改为值比较,或在状态未变化时不创建新 record;同时增加事件频率测试。~~ 已改为值比较(`old == newState`)。未新增专门的事件频率测试。
2. ~~明确 `_acquireQueue` 的职责:如果只是调试缓存,改为有限的轻量元数据/可配置采样;如果需要消费,则补齐消费者和释放策略。~~ 确认只是调试计数用途,已移除队列本体,改为原子饱和计数器。
3. ~~将 `PerformanceMonitorViewModel` 的匿名订阅改为具名处理器或保存 `SubscriptionToken`,在 `Dispose` 中完整解除订阅。~~ 已改为具名处理器 + `Dispose` 完整反订阅。
### 第三阶段:补齐状态闭环与生命周期
@@ -67,14 +67,30 @@
## 4. 验收标准
- 静止设备不再因无变化的 `MotionState` 每 100 ms 触发完整 UI 更新。
- 调试面板关闭后,旧 `PerformanceMonitorViewModel` 不再接收 AppState 事件。
- `_acquireQueue` 有明确消费者或明确的淘汰/禁用策略,运行时内存曲线可解释。
- BGA 流水线输出缺失时有可见错误,不再静默返回;编译器不再报告该方法的不可达代码。
- CNC 执行中权限判断、主界面状态和执行服务使用同一个状态来源。
- 硬件故障能够进入统一状态、日志和 UI 告警链路。
- [x] 静止设备不再因无变化的 `MotionState` 每 100 ms 触发完整 UI 更新。P0-2 已修复)
- [x] 调试面板关闭后,旧 `PerformanceMonitorViewModel` 不再接收 AppState 事件。P1-2 已修复)
- [x] `_acquireQueue` 有明确消费者或明确的淘汰/禁用策略,运行时内存曲线可解释。(P1-1 已修复:移除队列本体,改为纯计数)
- [x] BGA 流水线输出缺失时有可见错误,不再静默返回;编译器不再报告该方法的不可达代码。P0-1 已修复)
- [ ] CNC 执行中权限判断、主界面状态和执行服务使用同一个状态来源。(P1-5/P1-7,第三阶段,未开始)
- [ ] 硬件故障能够进入统一状态、日志和 UI 告警链路。P1-6,第三阶段,未开始)
## 5. 关联文档
第一、二阶段的四项已完成并通过 `dotnet build` 主项目编译验证;`XplorePlane.Tests` 因历史遗留的命名空间引用问题(`XplorePlane.Services.Logging`/`Diagnostics`/`Dialogs` 缺失)当前无法编译运行,与本次改动无关(改动前 `git stash` 验证同样报错),因此本轮未新增/运行自动化测试,也未验证 P1-3/P1-4/P2-3 等标注为“待验证”的问题。
## 5. 剩余事项(第三阶段,未开始)
- P1-3 `_latestGeometry` 跨线程同步风险待量化。
- P1-4 探测器断连状态判断的原子性待确认。
- P1-5 `CncExecutionStateChanged` 统一事实源。
- P1-6 硬件错误事件接入统一 `SystemState`
- P1-7 `OperationMode` 恒为 `Idle` 的权限守卫失效风险。
- P2-1 标定矩阵/画面联动子系统去留决策。
- P2-2 `WindowLauncherService.ShowOrActivateVisible` 窗口生命周期清理。
- P2-3 事件投递顺序与属性值一致性待验证。
- P2-4 `CncRoiEditRequestedPayload` 携带 `Action` 委托的设计风险。
- P2-5 探测器每帧复制大数组(`previewImage` 生成部分,与 `_acquireQueue` 无关的部分仍存在)。
- 修复 `XplorePlane.Tests` 的历史编译错误,恢复单测可运行,补齐 P0-1/P0-2/P1-1/P1-2 对应的自动化测试。
## 6. 关联文档
- [`doc/评估.md`](../评估.md):项目整体评估和既有死代码/占位实现清单。
- [`doc/archive/状态与事件流架构.md`](../archive/状态与事件流架构.md):AppState 与事件流架构说明。