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

295 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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"
```
---
## 🎯 最可能的原因(基于当前信息)
### 可能性 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()``kill`atexit 也不会触发,那时我们就知道要往那个方向调查了。
**请尽快测试并提供新日志!** 🎯