GrabBag/App/DroneScrewbolt/CRASH_FIX_SUMMARY.md
2026-06-26 17:55:15 +08:00

5.2 KiB
Raw Blame History

DroneScrewServer 崩溃问题修复总结

问题描述

程序在运行约 20 分钟后崩溃(退出码 255日志显示

  • 处理了约 2100 帧图像后突然退出
  • 没有任何错误日志,表明发生了未捕获的异常或段错误
  • 最后日志:right frame #2100 → 直接崩溃

根本原因分析

从代码审查发现以下风险点:

1. 相机回调函数缺少异常保护(最可能的原因)

  • leftCameraCallbackrightCameraCallback 在相机 SDK 线程中被调用
  • 包含内存分配、拷贝、RTSP 推流等操作,但没有 try-catch
  • 任何异常都会导致程序崩溃

2. 心跳日志内存信息不完整

  • procStatusValue("VmRSS") 返回空字符串
  • 无法监控内存增长情况

3. 算法库调用缺少保护

  • m_pAlgo->Detect() 可能抛出异常
  • 第三方算法库崩溃会导致整个进程退出

4. GPIO 触发线程缺少异常保护

  • 长时间运行的线程没有顶层异常捕获

修复方案

1. 相机回调异常保护(关键修复)

文件: DroneScrewServerPresenter.cpp

leftCameraCallback 函数

  • 整个函数体包裹在 try-catch
  • 捕获 std::bad_allocstd::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.cppdetectThreadFunc()

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.cpptriggerThreadFunc()

  • 整个 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 和错误信息
  • 将错误信息传递给结果对象

测试建议

  1. 长时运行测试

    • 运行 30 分钟以上,观察是否还会崩溃
    • 监控心跳日志中的内存变化
  2. 关键日志观察

    # 监控异常日志
    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"