7.2 KiB
7.2 KiB
DroneScrewServer 崩溃问题完整解决方案
📊 问题总结
问题 1:PNG 编码崩溃 ✅ 已解决
现象:
- 程序在检测模式下运行约 19 分钟后崩溃
- 崩溃发生在 PNG 编码过程中
- 日志显示:
[PUB-raw] before PNG encode→ 崩溃
根本原因:
- PNG 编码库在 ARM 平台处理 4096x3000 大图像时发生段错误
- OpenCV 或 libpng 的内部问题
解决方案:
- 禁用 PNG 压缩,使用原始格式传输
- 文件:
DroneScrewZmqProtocol.cpp - 修改:强制
usePng = false
影响:
- ✅ PNG 崩溃已完全解决
- ⚠️ 网络带宽从 ~10MB/帧 增加到 ~24MB/帧
- ✅ 千兆局域网完全足够(占用 38% 带宽)
问题 2:20 分钟定时崩溃 🔍 调查中
现象:
- 禁用 PNG 后,程序仍然在约 20 分钟后崩溃
- Idle 模式(完全空载)也崩溃
- 没有任何异常日志或错误信息
- 退出码:255
测试记录:
-
第一次崩溃(01:44:59):
- 运行时长:约 20 分钟
- 模式:检测模式(处理了 2041 帧)
- 最后日志:
[DETECT] frame #2041 after algo Detect, boxes=0
-
第二次崩溃(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
新增功能:
-
注册信号处理器捕获:
- SIGSEGV (段错误)
- SIGABRT (异常终止)
- SIGTERM (终止信号)
- SIGINT (中断)
- SIGILL (非法指令)
- SIGFPE (浮点异常)
- SIGBUS (总线错误)
- SIGPIPE (管道破裂)
-
崩溃时打印:
- 信号类型和编号
- 完整的调用栈(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() 或外部进程杀死
📋 后续调试方案
如果信号处理器捕获到了崩溃
根据调用栈分析:
- 如果调用栈中有
MV_CC_前缀 → MVS 相机 SDK 问题 - 如果调用栈中有
zmq_前缀 → ZeroMQ 问题 - 如果调用栈中有
ff_或av_前缀 → FFMedia/RTSP 问题 - 如果调用栈中有我们的代码 → 代码逻辑问题
如果信号处理器没有捕获到
说明不是信号导致,可能是:
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 深入分析
📞 下一步
请执行以下操作:
- ✅ 重新编译部署新版本(包含信号处理器)
- ✅ 运行至少 30 分钟,等待崩溃
- ✅ 提供完整日志,特别是崩溃前后的日志
- ✅ 查找
[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
💪 我们会找到根本原因的!
通过信号处理器和详细的调用栈,我们应该能够精确定位问题所在。请尽快测试并提供新的日志!