5.2 KiB
5.2 KiB
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)
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()
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
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 和错误信息
- 将错误信息传递给结果对象
测试建议
-
长时运行测试
- 运行 30 分钟以上,观察是否还会崩溃
- 监控心跳日志中的内存变化
-
关键日志观察
# 监控异常日志 grep -E "exception|unknown exception|bad_alloc" log.log # 监控内存增长 grep "HEARTBEAT" log.log # 监控内存重新分配 grep "realloc" log.log -
预期结果
- 如果是相机回调异常:会看到
[CAM] left/right callback exception但程序不崩溃 - 如果是算法异常:会看到
[DETECT] algo exception但程序继续运行 - 如果是内存泄漏:心跳日志会显示内存持续增长
- 如果是 GPIO 异常:会看到
[GPIO] trigger thread exception但程序不崩溃
- 如果是相机回调异常:会看到
下一步行动
- 编译并部署修改后的代码
- 运行至少 30 分钟,观察日志
- 记录所有异常日志,分析根本原因
- 根据日志反馈进行针对性修复
注意事项
- 所有异常捕获都会记录日志,不会静默失败
- 异常保护只是防止崩溃,并不解决根本问题
- 看到异常日志后需要进一步分析根本原因
- 如果频繁出现异常,说明存在更深层的问题需要修复
修改文件清单
-
App/DroneScrewbolt/DroneScrewServer/DroneScrewServerPresenter.cppleftCameraCallback()- 增加异常保护和内存重分配日志rightCameraCallback()- 增加异常保护和内存重分配日志detectThreadFunc()- 算法调用增加异常保护triggerThreadFunc()- 增加异常保护
-
App/DroneScrewbolt/DroneScrewServer/main.cpp- 心跳日志增强:增加 vmPeak、vmSize 字段
- 处理空值显示为 "N/A"