# DroneScrewServer 20分钟崩溃 - 最终调试版本 ## 🔍 当前状态 ### 已确认的信息 1. ✅ **PNG 崩溃已解决** - 禁用 PNG 压缩后不再有 PNG 相关崩溃 2. ✅ **信号处理器已注册** - 但崩溃时**没有触发** 3. ❌ **程序仍然在 20 分钟后崩溃** - 退出码 255 4. ❌ **没有任何异常日志** - 所有 try-catch 未触发 5. ❌ **没有信号日志** - signalHandler 未被调用 ### 最新发现 **崩溃时的最后日志**: ``` [DETECT] frame #2163 after rawImageReady emit [DETECT] frame #2163 before algo Detect, left=2242 right=19 [DETECT] frame #2163 after algo Detect, boxes=0 Main process exited, status=255/EXCEPTION ``` **关键发现**: - ✅ `after algo Detect` 日志完成 - ❌ **没有 `after detectionResult emit` 日志** - ❌ 没有信号处理器日志 **结论**:崩溃发生在 `emit detectionResult(result)` 这一行,但**不是通过信号触发的**! --- ## 🎯 新增的调试功能(v3) ### 1. atexit 处理器 **目的**:捕获正常退出(通过 `exit()` 或 `return`) **功能**: - 程序退出时自动调用 - 打印完整的退出调用栈 - 告诉我们是谁调用了 exit() **预期日志**: ``` [ATEXIT] Program is exiting normally! [ATEXIT-BACKTRACE] Exit call stack (N frames): [0] atexitHandler+0x... [1] exit+0x... [2] 某个函数+0x... ← 这就是罪魁祸首! ``` ### 2. 检测线程详细日志 **新增日志点**: ```cpp emit detectionResult(result); LOG_DEBUG("[DETECT] frame #%d after detectionResult emit\n", ...); ← 新增 ... LOG_DEBUG("[DETECT] frame #%d loop end, checking exit flag=%d\n", ...); ← 新增 ``` **目的**: - 确认是否是 `emit detectionResult` 导致崩溃 - 检查循环是否正常继续 - 监控线程退出标志 --- ## 🧪 测试步骤 ### 1. 编译部署新版本 ```bash cd GrabBagPrj qmake GrabBagPrj.pro make # 部署到设备 scp App/DroneScrewbolt/DroneScrewServer/DroneScrewServer user@device:/path/to/ ``` ### 2. 运行测试 ```bash # 重启服务 sudo systemctl restart dronescrewserver # 实时查看日志 sudo journalctl -u dronescrewserver.service -f | tee /tmp/dronescrew_test.log ``` ### 3. 等待崩溃(约 20 分钟) ### 4. 分析日志 查找关键日志: ```bash # 1. 查找 atexit 日志 grep -A 30 "\[ATEXIT\]" /tmp/dronescrew_test.log # 2. 查找信号日志 grep -A 30 "\[SIGNAL\]" /tmp/dronescrew_test.log # 3. 查找崩溃前的最后日志 grep -B 20 "Main process exited" /tmp/dronescrew_test.log ``` --- ## 📊 预期结果分析 ### 场景 A:看到 atexit 日志 ``` [DETECT] frame #2163 after algo Detect, boxes=0 [ATEXIT] Program is exiting normally! [ATEXIT-BACKTRACE] Exit call stack (15 frames): [0] atexitHandler+0x123 [1] __run_exit_handlers+0x456 [2] exit+0x789 [3] QCoreApplication::exit+0xabc ← Qt 事件循环退出 [4] 某个槽函数+0xdef ``` **说明**: - 有代码主动调用了 `exit()` 或 `QCoreApplication::exit()` - 调用栈会告诉我们是哪个函数 **可能的原因**: 1. `publishDetectionResult` 中某处调用了 exit 2. Qt 信号槽机制触发了某个会退出的代码 3. 第三方库内部调用了 exit ### 场景 B:看到信号日志 ``` [DETECT] frame #2163 after algo Detect, boxes=0 [SIGNAL] Caught signal 11: SIGSEGV (Segmentation Fault) [BACKTRACE] Stack trace (20 frames): [0] signalHandler+0x123 [1] /lib/libc.so+0x456 [2] 某个函数+0x789 ← 崩溃点 ``` **说明**: - 是信号导致的崩溃(段错误、总线错误等) - 但之前的测试没有捕获到,可能之前版本没有正确注册 ### 场景 C:既没有 atexit 也没有 signal ``` [DETECT] frame #2163 after algo Detect, boxes=0 Main process exited, status=255/EXCEPTION ``` **说明**: - 程序被外部强制终止(`_exit()` 或 `kill`) - `_exit()` 不会触发 atexit 处理器 - 需要使用其他方法调试 **下一步**: 1. 使用 `strace` 跟踪系统调用 2. 检查是否有其他进程杀死了这个进程 3. 检查 systemd 的 cgroup 限制 ### 场景 D:看到 "after detectionResult emit" ``` [DETECT] frame #2163 after algo Detect, boxes=0 [DETECT] frame #2163 after detectionResult emit ← 新日志 [DETECT] frame #2163 loop end, checking exit flag=0 [DETECT] frame #2164 before rawImageReady emit (崩溃在其他地方) ``` **说明**: - `emit detectionResult` 不是直接原因 - 崩溃发生在后续的某个地方 - 需要继续增加日志 --- ## 🔬 根据测试结果的下一步方案 ### 如果有 atexit 日志 → **根据调用栈定位调用 exit 的代码** → 修复或注释掉那个 exit 调用 → 问题解决 ### 如果有 signal 日志 → **根据调用栈定位崩溃的函数** → 修复段错误或内存问题 → 问题解决 ### 如果都没有 → **使用 strace 跟踪系统调用**: ```bash sudo strace -f -tt -T -o /tmp/strace.log \ -e trace=exit,exit_group,kill,tkill,tgkill \ /path/to/DroneScrewServer ``` → **查看是否有外部进程杀死**: ```bash # 查看系统日志 dmesg | grep -i "killed\|oom" # 查看 audit 日志 sudo ausearch -m ANOM_ABEND -ts recent ``` → **检查 cgroup 限制**: ```bash systemctl show dronescrewserver.service | grep -i "memory\|cpu\|tasks" ``` --- ## 🎯 最可能的原因(基于当前信息) ### 可能性 1:Qt 信号槽机制问题(60%) `detectionResult` 信号通过 Qt::AutoConnection 从**检测线程**发送到**主线程**的槽函数。可能: 1. Qt 的事件队列满了导致崩溃 2. 跨线程信号槽的内部问题 3. 槽函数中有问题的代码 **验证方法**:改用 Qt::QueuedConnection 明确指定队列连接 ### 可能性 2:publishDetectionResult 内部问题(30%) 虽然有异常保护,但可能: 1. ZeroMQ 内部调用了 `_exit()` 2. QJsonDocument 序列化时崩溃 3. 互斥锁死锁导致问题 **验证方法**:临时注释掉整个函数体,看是否还崩溃 ### 可能性 3:第三方库的定时任务(10%) MVS SDK 或其他库的后台线程在 20 分钟后执行某个操作导致崩溃。 **验证方法**:使用 strace 或 gdb 附加到进程 --- ## 📝 修改文件清单 ### 本次修改(v3) 1. `main.cpp` - 增加 `atexitHandler()` - 捕获正常退出 - 注册 `atexit()` 处理器 2. `DroneScrewServerPresenter.cpp` - 增加 `after detectionResult emit` 日志 - 增加 `loop end` 日志 ### 累计修改 | 文件 | 修改内容 | 版本 | |------|---------|------| | `DroneScrewZmqProtocol.cpp` | 禁用 PNG 压缩 | v1 | | `DroneScrewServerPresenter.cpp` | 详细检测日志 | v1 | | `DroneScrewZmqProtocol.cpp` | PNG/ZMQ 日志 | v1 | | `main.cpp` | 信号处理器 | v2 | | `main.cpp` | atexit 处理器 | v3 ⭐ | | `DroneScrewServerPresenter.cpp` | emit 后日志 | v3 ⭐ | --- ## 🚀 立即行动 1. ✅ **编译部署** v3 版本 2. ✅ **运行测试** 至少 30 分钟 3. ✅ **查找关键字**: - `[ATEXIT]` - 正常退出 - `[SIGNAL]` - 信号崩溃 - `after detectionResult emit` - emit 是否完成 4. ✅ **提供完整日志** --- ## 💪 我们越来越接近真相了! 通过 atexit 处理器,我们**一定能找到**是谁调用了 exit()! 如果程序是被外部强制终止的(`_exit()` 或 `kill`),atexit 也不会触发,那时我们就知道要往那个方向调查了。 **请尽快测试并提供新日志!** 🎯