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

7.2 KiB
Raw Blame History

DroneScrewServer 崩溃问题完整解决方案

📊 问题总结

问题 1PNG 编码崩溃 已解决

现象

  • 程序在检测模式下运行约 19 分钟后崩溃
  • 崩溃发生在 PNG 编码过程中
  • 日志显示:[PUB-raw] before PNG encode → 崩溃

根本原因

  • PNG 编码库在 ARM 平台处理 4096x3000 大图像时发生段错误
  • OpenCV 或 libpng 的内部问题

解决方案

  • 禁用 PNG 压缩,使用原始格式传输
  • 文件:DroneScrewZmqProtocol.cpp
  • 修改:强制 usePng = false

影响

  • PNG 崩溃已完全解决
  • ⚠️ 网络带宽从 ~10MB/帧 增加到 ~24MB/帧
  • 千兆局域网完全足够(占用 38% 带宽)

问题 220 分钟定时崩溃 🔍 调查中

现象

  • 禁用 PNG 后,程序仍然在约 20 分钟后崩溃
  • Idle 模式(完全空载)也崩溃
  • 没有任何异常日志或错误信息
  • 退出码255

测试记录

  1. 第一次崩溃01:44:59

    • 运行时长:约 20 分钟
    • 模式:检测模式(处理了 2041 帧)
    • 最后日志:[DETECT] frame #2041 after algo Detect, boxes=0
  2. 第二次崩溃02:05:05

    • 运行时长1140 秒19 分钟)
    • 模式Idle完全空载未启动检测
    • 最后日志:[HEARTBEAT] uptime=1140s mode=idle

关键特征

  • 时间规律:精确的 20 分钟间隔
  • 与业务逻辑无关:空载也崩溃
  • 没有异常日志:所有 try-catch 未触发
  • 业务流程完整:所有日志正常

排除的原因

  • 不是 PNG 编码问题(已禁用)
  • 不是内存泄漏htop 显示 < 1GB
  • 不是检测算法问题idle 也崩溃)
  • 不是异常退出(没有异常日志)
  • 不是 systemd 配置(服务文件没有超时设置)

可能的原因

1. 未捕获的信号(最可能)

  • 段错误SIGSEGV
  • 总线错误SIGBUS
  • 非法指令SIGILL
  • 其他致命信号

2. 第三方库内部问题

  • MVS 相机 SDK - 后台线程可能有 20 分钟的定时操作
  • ZeroMQ - 内部定时器或清理任务
  • FFMedia (RTSP) - 推流相关的定时任务
  • Qt 框架 - 事件循环或内部定时器

3. 硬件或驱动问题

  • USB 相机驱动在 20 分钟后触发某个问题
  • GPIO 相关的驱动问题
  • 系统资源限制

🛠️ 最新解决方案

方案 A增加信号处理器已实施

目的:捕获导致崩溃的信号,打印调用栈

修改文件main.cpp

新增功能

  1. 注册信号处理器捕获:

    • SIGSEGV (段错误)
    • SIGABRT (异常终止)
    • SIGTERM (终止信号)
    • SIGINT (中断)
    • SIGILL (非法指令)
    • SIGFPE (浮点异常)
    • SIGBUS (总线错误)
    • SIGPIPE (管道破裂)
  2. 崩溃时打印:

    • 信号类型和编号
    • 完整的调用栈backtrace
    • 30 层函数调用

预期效果

  • 如果是信号导致崩溃,会看到:
    [SIGNAL] Caught signal X: SIGXXX (Description)
    [BACKTRACE] Stack trace (N frames):
      [0] function_name+0xoffset
      [1] function_name+0xoffset
      ...
    

🧪 测试步骤

1. 重新编译部署

cd GrabBagPrj
qmake GrabBagPrj.pro
make

# 部署到设备
scp App/DroneScrewbolt/DroneScrewServer/DroneScrewServer user@device:/path/to/

2. 运行测试

# 重启服务
sudo systemctl restart dronescrewserver

# 实时查看日志
sudo journalctl -u dronescrewserver.service -f

3. 等待崩溃(约 20 分钟)

观察日志中是否出现:

  • [SIGNAL] Caught signal X - 说明捕获到信号
  • [BACKTRACE] Stack trace - 崩溃时的调用栈

4. 分析结果

场景 A看到信号日志

[SIGNAL] Caught signal 11: SIGSEGV (Segmentation Fault)
[BACKTRACE] Stack trace (15 frames):
  [0] signalHandler+0x123
  [1] /lib/libc.so+0x456
  [2] MV_CC_SomeFunction+0x789  ← 相机 SDK
  ...

根据调用栈定位问题

场景 B没有信号日志直接退出

可能是 _exit() 或外部进程杀死


📋 后续调试方案

如果信号处理器捕获到了崩溃

根据调用栈分析:

  1. 如果调用栈中有 MV_CC_ 前缀 → MVS 相机 SDK 问题
  2. 如果调用栈中有 zmq_ 前缀 → ZeroMQ 问题
  3. 如果调用栈中有 ff_av_ 前缀 → FFMedia/RTSP 问题
  4. 如果调用栈中有我们的代码 → 代码逻辑问题

如果信号处理器没有捕获到

说明不是信号导致,可能是:

1. 启用 coredump

# 设置 coredump
ulimit -c unlimited
sudo mkdir -p /var/coredumps
echo '/var/coredumps/core.%e.%p.%t' | sudo tee /proc/sys/kernel/core_pattern

# 修改服务
sudo systemctl edit dronescrewserver.service
# 添加:
[Service]
LimitCORE=infinity

# 重启
sudo systemctl daemon-reload
sudo systemctl restart dronescrewserver

# 崩溃后分析
gdb /path/to/DroneScrewServer /var/coredumps/core.xxx.xxx.xxx
(gdb) bt
(gdb) thread apply all bt

2. 使用 strace 跟踪系统调用

sudo strace -f -tt -T -o /tmp/strace.log /path/to/DroneScrewServer

3. 使用 valgrind 检查内存问题

valgrind --leak-check=full --track-origins=yes /path/to/DroneScrewServer

4. 临时禁用相机回调测试

如果怀疑是 MVS SDK 问题,可以临时注释掉相机初始化,看是否还崩溃:

// presenter.initAll();  // 临时注释

5. 禁用 RTSP 推流测试

// m_pPusher = ...;  // 临时设置为 nullptr

📊 修改文件清单

已修改的文件

文件 修改内容 状态
DroneScrewZmqProtocol.cpp 禁用 PNG 压缩 完成
DroneScrewServerPresenter.cpp 增加检测流程详细日志 完成
main.cpp 增加信号处理器和调用栈打印 完成

文档

文档 说明
CRASH_FIX_SUMMARY.md 第一轮异常保护总结
DIAGNOSTIC_LOG_ENHANCEMENT.md 诊断日志增强说明
CRASH_ROOT_CAUSE_ANALYSIS.md PNG 崩溃根因分析
CRASH_20MIN_TIMEOUT_ANALYSIS.md 20 分钟崩溃分析
CRASH_FINAL_SOLUTION.md 完整解决方案(本文档)

🎯 预期结果

运行新版本后

如果是信号导致崩溃

  • 日志中会出现 [SIGNAL] Caught signal X
  • 会有完整的调用栈
  • 可以立即定位问题

如果不是信号导致

  • 继续按照后续调试方案进行
  • 使用 coredump 或 strace 深入分析

📞 下一步

请执行以下操作

  1. 重新编译部署新版本(包含信号处理器)
  2. 运行至少 30 分钟,等待崩溃
  3. 提供完整日志,特别是崩溃前后的日志
  4. 查找 [SIGNAL] 关键字,看是否捕获到信号

关键日志命令

# 查看最近 2 小时的日志
sudo journalctl -u dronescrewserver.service --since "2 hours ago" > /tmp/crash.log

# 查找信号相关日志
grep -A 50 "\[SIGNAL\]" /tmp/crash.log

# 查找崩溃相关日志
grep -B 30 -A 10 "Main process exited" /tmp/crash.log

💪 我们会找到根本原因的!

通过信号处理器和详细的调用栈,我们应该能够精确定位问题所在。请尽快测试并提供新的日志!