290 lines
7.2 KiB
Markdown
290 lines
7.2 KiB
Markdown
# 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
|
||
|
||
**测试记录**:
|
||
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. 重新编译部署
|
||
|
||
```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
|
||
```
|
||
|
||
### 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
|
||
```bash
|
||
# 设置 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 跟踪系统调用
|
||
```bash
|
||
sudo strace -f -tt -T -o /tmp/strace.log /path/to/DroneScrewServer
|
||
```
|
||
|
||
#### 3. 使用 valgrind 检查内存问题
|
||
```bash
|
||
valgrind --leak-check=full --track-origins=yes /path/to/DroneScrewServer
|
||
```
|
||
|
||
#### 4. 临时禁用相机回调测试
|
||
|
||
如果怀疑是 MVS SDK 问题,可以临时注释掉相机初始化,看是否还崩溃:
|
||
|
||
```cpp
|
||
// presenter.initAll(); // 临时注释
|
||
```
|
||
|
||
#### 5. 禁用 RTSP 推流测试
|
||
|
||
```cpp
|
||
// 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]` 关键字**,看是否捕获到信号
|
||
|
||
**关键日志命令**:
|
||
```bash
|
||
# 查看最近 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
|
||
```
|
||
|
||
---
|
||
|
||
## 💪 我们会找到根本原因的!
|
||
|
||
通过信号处理器和详细的调用栈,我们应该能够精确定位问题所在。请尽快测试并提供新的日志!
|