183 lines
5.2 KiB
Markdown
183 lines
5.2 KiB
Markdown
# DroneScrewServer 崩溃问题修复总结
|
||
|
||
## 问题描述
|
||
|
||
程序在运行约 20 分钟后崩溃(退出码 255),日志显示:
|
||
- 处理了约 2100 帧图像后突然退出
|
||
- 没有任何错误日志,表明发生了未捕获的异常或段错误
|
||
- 最后日志:`right frame #2100` → 直接崩溃
|
||
|
||
## 根本原因分析
|
||
|
||
从代码审查发现以下风险点:
|
||
|
||
### 1. **相机回调函数缺少异常保护**(最可能的原因)
|
||
- `leftCameraCallback` 和 `rightCameraCallback` 在相机 SDK 线程中被调用
|
||
- 包含内存分配、拷贝、RTSP 推流等操作,但没有 try-catch
|
||
- 任何异常都会导致程序崩溃
|
||
|
||
### 2. **心跳日志内存信息不完整**
|
||
- `procStatusValue("VmRSS")` 返回空字符串
|
||
- 无法监控内存增长情况
|
||
|
||
### 3. **算法库调用缺少保护**
|
||
- `m_pAlgo->Detect()` 可能抛出异常
|
||
- 第三方算法库崩溃会导致整个进程退出
|
||
|
||
### 4. **GPIO 触发线程缺少异常保护**
|
||
- 长时间运行的线程没有顶层异常捕获
|
||
|
||
## 修复方案
|
||
|
||
### 1. 相机回调异常保护(关键修复)
|
||
|
||
**文件**: `DroneScrewServerPresenter.cpp`
|
||
|
||
#### `leftCameraCallback` 函数
|
||
- 整个函数体包裹在 `try-catch` 中
|
||
- 捕获 `std::bad_alloc`、`std::exception` 和未知异常
|
||
- 增加内存重新分配的日志(realloc log)
|
||
|
||
```cpp
|
||
void DroneScrewServerPresenter::leftCameraCallback(const MvsImageData& img)
|
||
{
|
||
try
|
||
{
|
||
// ... 原有逻辑 ...
|
||
}
|
||
catch (const std::bad_alloc& e)
|
||
{
|
||
LOG_ERROR("[CAM] left callback bad_alloc frame=%llu size=%zu: %s\n", ...);
|
||
}
|
||
catch (const std::exception& e)
|
||
{
|
||
LOG_ERROR("[CAM] left callback exception frame=%llu: %s\n", ...);
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_ERROR("[CAM] left callback unknown exception frame=%llu\n", ...);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### `rightCameraCallback` 函数
|
||
- 同样增加异常保护
|
||
- 增加内存重新分配的日志
|
||
|
||
### 2. 算法调用异常保护
|
||
|
||
**文件**: `DroneScrewServerPresenter.cpp` → `detectThreadFunc()`
|
||
|
||
```cpp
|
||
if (m_pAlgo)
|
||
{
|
||
try
|
||
{
|
||
m_pAlgo->Detect(inLeft, inRight, result);
|
||
}
|
||
catch (const std::exception& e)
|
||
{
|
||
LOG_ERROR("[DETECT] algo exception frame=%llu: %s\n", ...);
|
||
result.success = false;
|
||
result.errorCode = -1;
|
||
result.message = std::string("Algorithm exception: ") + e.what();
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_ERROR("[DETECT] algo unknown exception frame=%llu\n", ...);
|
||
// ... 设置错误状态 ...
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. GPIO 触发线程异常保护
|
||
|
||
**文件**: `DroneScrewServerPresenter.cpp` → `triggerThreadFunc()`
|
||
|
||
- 整个 while 循环包裹在 try-catch 中
|
||
- 防止 GPIO 操作异常导致程序崩溃
|
||
|
||
### 4. 增强心跳日志
|
||
|
||
**文件**: `main.cpp`
|
||
|
||
```cpp
|
||
const QString rss = procStatusValue("VmRSS");
|
||
const QString vmPeak = procStatusValue("VmPeak");
|
||
const QString vmSize = procStatusValue("VmSize");
|
||
const QString threads = procStatusValue("Threads");
|
||
LOG_INFO("[HEARTBEAT] uptime=%llds mode=%s rss=%s vmPeak=%s vmSize=%s threads=%s\n",
|
||
...,
|
||
rss.isEmpty() ? "N/A" : rss.toStdString().c_str(),
|
||
...);
|
||
```
|
||
|
||
增加的字段:
|
||
- `vmPeak`: 峰值虚拟内存
|
||
- `vmSize`: 当前虚拟内存
|
||
- 空值显示为 "N/A" 而非空字符串
|
||
|
||
## 诊断日志增强
|
||
|
||
### 相机回调
|
||
- 内存重新分配时打印旧/新 size
|
||
- 异常时记录帧 ID、数据大小和异常信息
|
||
|
||
### 心跳监控
|
||
- 显示内存使用趋势(RSS、VmPeak、VmSize)
|
||
- 线程数量监控
|
||
|
||
### 算法调用
|
||
- 异常时记录帧 ID 和错误信息
|
||
- 将错误信息传递给结果对象
|
||
|
||
## 测试建议
|
||
|
||
1. **长时运行测试**
|
||
- 运行 30 分钟以上,观察是否还会崩溃
|
||
- 监控心跳日志中的内存变化
|
||
|
||
2. **关键日志观察**
|
||
```bash
|
||
# 监控异常日志
|
||
grep -E "exception|unknown exception|bad_alloc" log.log
|
||
|
||
# 监控内存增长
|
||
grep "HEARTBEAT" log.log
|
||
|
||
# 监控内存重新分配
|
||
grep "realloc" log.log
|
||
```
|
||
|
||
3. **预期结果**
|
||
- 如果是相机回调异常:会看到 `[CAM] left/right callback exception` 但程序不崩溃
|
||
- 如果是算法异常:会看到 `[DETECT] algo exception` 但程序继续运行
|
||
- 如果是内存泄漏:心跳日志会显示内存持续增长
|
||
- 如果是 GPIO 异常:会看到 `[GPIO] trigger thread exception` 但程序不崩溃
|
||
|
||
## 下一步行动
|
||
|
||
1. **编译并部署**修改后的代码
|
||
2. **运行至少 30 分钟**,观察日志
|
||
3. **记录所有异常日志**,分析根本原因
|
||
4. **根据日志反馈**进行针对性修复
|
||
|
||
## 注意事项
|
||
|
||
- 所有异常捕获都会记录日志,不会静默失败
|
||
- 异常保护只是防止崩溃,并不解决根本问题
|
||
- 看到异常日志后需要进一步分析根本原因
|
||
- 如果频繁出现异常,说明存在更深层的问题需要修复
|
||
|
||
## 修改文件清单
|
||
|
||
1. `App/DroneScrewbolt/DroneScrewServer/DroneScrewServerPresenter.cpp`
|
||
- `leftCameraCallback()` - 增加异常保护和内存重分配日志
|
||
- `rightCameraCallback()` - 增加异常保护和内存重分配日志
|
||
- `detectThreadFunc()` - 算法调用增加异常保护
|
||
- `triggerThreadFunc()` - 增加异常保护
|
||
|
||
2. `App/DroneScrewbolt/DroneScrewServer/main.cpp`
|
||
- 心跳日志增强:增加 vmPeak、vmSize 字段
|
||
- 处理空值显示为 "N/A"
|