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

7.3 KiB
Raw Blame History

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. 检测线程详细日志

新增日志点

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. 编译部署新版本

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 | tee /tmp/dronescrew_test.log

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

4. 分析日志

查找关键日志:

# 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 跟踪系统调用

sudo strace -f -tt -T -o /tmp/strace.log \
  -e trace=exit,exit_group,kill,tkill,tgkill \
  /path/to/DroneScrewServer

查看是否有外部进程杀死

# 查看系统日志
dmesg | grep -i "killed\|oom"

# 查看 audit 日志
sudo ausearch -m ANOM_ABEND -ts recent

检查 cgroup 限制

systemctl show dronescrewserver.service | grep -i "memory\|cpu\|tasks"

🎯 最可能的原因(基于当前信息)

可能性 1Qt 信号槽机制问题60%

detectionResult 信号通过 Qt::AutoConnection 从检测线程发送到主线程的槽函数。可能:

  1. Qt 的事件队列满了导致崩溃
  2. 跨线程信号槽的内部问题
  3. 槽函数中有问题的代码

验证方法:改用 Qt::QueuedConnection 明确指定队列连接

可能性 2publishDetectionResult 内部问题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()killatexit 也不会触发,那时我们就知道要往那个方向调查了。

请尽快测试并提供新日志! 🎯