260 lines
6.7 KiB
Markdown
260 lines
6.7 KiB
Markdown
|
|
# DroneScrewServer 崩溃根因最终分析
|
|||
|
|
|
|||
|
|
## 🎯 最新发现(2026-06-04)
|
|||
|
|
|
|||
|
|
### 崩溃模式确认
|
|||
|
|
|
|||
|
|
经过多次测试和日志分析,发现了以下关键信息:
|
|||
|
|
|
|||
|
|
#### 测试 1:PNG 编码崩溃(已解决)
|
|||
|
|
- **崩溃点**:`[PUB-raw] before PNG encode`
|
|||
|
|
- **原因**:PNG 编码库段错误
|
|||
|
|
- **解决方案**:禁用 PNG 压缩
|
|||
|
|
- **状态**:✅ 已修复
|
|||
|
|
|
|||
|
|
#### 测试 2:禁用 PNG 后仍崩溃(新问题)
|
|||
|
|
|
|||
|
|
**第一次崩溃(01:44:59)**:
|
|||
|
|
```
|
|||
|
|
运行时长:约 20 分钟
|
|||
|
|
模式:检测模式
|
|||
|
|
最后日志:[DETECT] frame #2041 after algo Detect, boxes=0
|
|||
|
|
退出码:255
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**第二次崩溃(02:05:05)**:
|
|||
|
|
```
|
|||
|
|
运行时长:约 20 分钟(1140秒)
|
|||
|
|
模式:Idle(完全空载)
|
|||
|
|
最后日志:[HEARTBEAT] uptime=1140s mode=idle
|
|||
|
|
退出码:255
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 🔍 关键线索
|
|||
|
|
|
|||
|
|
1. **时间规律性**:
|
|||
|
|
- 两次崩溃都在启动后约 **19-20 分钟**
|
|||
|
|
- 与是否运行检测**无关**
|
|||
|
|
- 与处理的帧数**无关**
|
|||
|
|
|
|||
|
|
2. **Idle 模式也崩溃**:
|
|||
|
|
- 程序完全空载(没有检测、没有图像处理)
|
|||
|
|
- 仅运行心跳日志
|
|||
|
|
- 说明**不是业务逻辑代码的问题**
|
|||
|
|
|
|||
|
|
3. **没有异常日志**:
|
|||
|
|
- 所有 try-catch 都没有捕获到异常
|
|||
|
|
- 所有业务流程日志都完整
|
|||
|
|
- 崩溃发生在**代码逻辑之外**
|
|||
|
|
|
|||
|
|
## 💡 根本原因推断
|
|||
|
|
|
|||
|
|
### 最可能的原因:systemd 看门狗或超时配置
|
|||
|
|
|
|||
|
|
#### 证据:
|
|||
|
|
1. **精确的 20 分钟间隔**:不像随机崩溃,更像超时强制终止
|
|||
|
|
2. **退出码 255**:异常退出,但非段错误(段错误通常是 139)
|
|||
|
|
3. **systemd 日志**:`Main process exited, code=exited, status=255/EXCEPTION`
|
|||
|
|
4. **Idle 也崩溃**:排除了所有业务代码问题
|
|||
|
|
|
|||
|
|
#### systemd 可能的配置:
|
|||
|
|
```ini
|
|||
|
|
[Service]
|
|||
|
|
RuntimeMaxSec=20m # 运行时间上限 20 分钟
|
|||
|
|
# 或
|
|||
|
|
WatchdogSec=20m # 看门狗超时 20 分钟
|
|||
|
|
# 或
|
|||
|
|
TimeoutStopSec=20m # 停止超时
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 其他可能性(概率较低)
|
|||
|
|
|
|||
|
|
#### 1. Qt 事件循环死锁
|
|||
|
|
- Qt 主事件循环卡死
|
|||
|
|
- 某个线程持有锁不释放
|
|||
|
|
- 但这通常不会有精确的 20 分钟间隔
|
|||
|
|
|
|||
|
|
#### 2. 内存泄漏导致 OOM-Killer
|
|||
|
|
- 但 htop 显示内存 < 1GB
|
|||
|
|
- 而且 OOM-Killer 的退出码通常是 9 (SIGKILL)
|
|||
|
|
|
|||
|
|
#### 3. 相机 SDK 内部问题
|
|||
|
|
- MVS SDK 的后台线程崩溃
|
|||
|
|
- 但为什么会是精确的 20 分钟?
|
|||
|
|
|
|||
|
|
## 🛠️ 解决方案
|
|||
|
|
|
|||
|
|
### 方案 1:检查 systemd 服务配置(优先)
|
|||
|
|
|
|||
|
|
**步骤**:
|
|||
|
|
```bash
|
|||
|
|
# 查看当前服务配置
|
|||
|
|
sudo systemctl cat dronescrewserver.service
|
|||
|
|
|
|||
|
|
# 查看完整状态
|
|||
|
|
sudo systemctl status dronescrewserver.service
|
|||
|
|
|
|||
|
|
# 查看服务属性
|
|||
|
|
sudo systemctl show dronescrewserver.service | grep -i "timeout\|watchdog\|runtime"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**如果发现超时配置,修改服务文件**:
|
|||
|
|
```ini
|
|||
|
|
[Service]
|
|||
|
|
# 移除或增加运行时间限制
|
|||
|
|
# RuntimeMaxSec=infinity # 或设置更长时间
|
|||
|
|
# WatchdogSec=0 # 禁用看门狗
|
|||
|
|
|
|||
|
|
# 增加停止超时(避免强制杀死)
|
|||
|
|
TimeoutStopSec=30s
|
|||
|
|
|
|||
|
|
# 重启策略
|
|||
|
|
Restart=always
|
|||
|
|
RestartSec=5s
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**应用配置**:
|
|||
|
|
```bash
|
|||
|
|
sudo systemctl daemon-reload
|
|||
|
|
sudo systemctl restart dronescrewserver
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 方案 2:启用 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
|
|||
|
|
|
|||
|
|
# 修改 systemd 服务
|
|||
|
|
sudo systemctl edit dronescrewserver.service
|
|||
|
|
|
|||
|
|
# 添加:
|
|||
|
|
[Service]
|
|||
|
|
LimitCORE=infinity
|
|||
|
|
|
|||
|
|
# 重启
|
|||
|
|
sudo systemctl daemon-reload
|
|||
|
|
sudo systemctl restart dronescrewserver
|
|||
|
|
|
|||
|
|
# 崩溃后查看 coredump
|
|||
|
|
ls -lh /var/coredumps/
|
|||
|
|
# 使用 gdb 分析
|
|||
|
|
gdb /path/to/DroneScrewServer /var/coredumps/core.xxx
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 方案 3:增加详细的系统调用跟踪
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 使用 strace 跟踪(会影响性能)
|
|||
|
|
sudo systemctl stop dronescrewserver
|
|||
|
|
sudo strace -f -o /tmp/dronescrew_strace.log /path/to/DroneScrewServer
|
|||
|
|
|
|||
|
|
# 或修改 systemd 服务
|
|||
|
|
[Service]
|
|||
|
|
ExecStart=/usr/bin/strace -f -o /tmp/dronescrew_strace.log /path/to/DroneScrewServer
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 方案 4:修改代码增加信号处理器
|
|||
|
|
|
|||
|
|
在 `main.cpp` 中增加信号处理,捕获崩溃信号:
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
#include <signal.h>
|
|||
|
|
#include <execinfo.h>
|
|||
|
|
|
|||
|
|
void signalHandler(int sig)
|
|||
|
|
{
|
|||
|
|
void* array[20];
|
|||
|
|
size_t size = backtrace(array, 20);
|
|||
|
|
|
|||
|
|
LOG_ERROR("========== SIGNAL %d RECEIVED ==========\n", sig);
|
|||
|
|
LOG_ERROR("Stack trace:\n");
|
|||
|
|
|
|||
|
|
char** messages = backtrace_symbols(array, size);
|
|||
|
|
for (size_t i = 0; i < size; i++)
|
|||
|
|
LOG_ERROR(" [%zu] %s\n", i, messages[i]);
|
|||
|
|
free(messages);
|
|||
|
|
|
|||
|
|
exit(sig);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int main(int argc, char* argv[])
|
|||
|
|
{
|
|||
|
|
// 注册信号处理器
|
|||
|
|
signal(SIGSEGV, signalHandler); // 段错误
|
|||
|
|
signal(SIGABRT, signalHandler); // 异常终止
|
|||
|
|
signal(SIGTERM, signalHandler); // 终止信号
|
|||
|
|
signal(SIGKILL, signalHandler); // 强制终止(无法捕获,但尝试)
|
|||
|
|
|
|||
|
|
// ... 原有代码 ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📊 优先级和推荐
|
|||
|
|
|
|||
|
|
### 立即执行(优先级 P0)
|
|||
|
|
|
|||
|
|
1. **检查 systemd 服务配置**
|
|||
|
|
```bash
|
|||
|
|
sudo systemctl show dronescrewserver.service | grep -i "timeout\|watchdog\|runtime"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **查看完整的 systemd 日志**
|
|||
|
|
```bash
|
|||
|
|
sudo journalctl -u dronescrewserver.service --since "1 hour ago" | grep -i "timeout\|killed\|signal"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 短期(优先级 P1)
|
|||
|
|
|
|||
|
|
3. **启用 coredump**(如果是段错误)
|
|||
|
|
4. **增加信号处理器**(捕获终止信号)
|
|||
|
|
|
|||
|
|
### 中期(优先级 P2)
|
|||
|
|
|
|||
|
|
5. **代码审查**:
|
|||
|
|
- 检查是否有死锁可能
|
|||
|
|
- 检查线程退出逻辑
|
|||
|
|
- 检查资源清理
|
|||
|
|
|
|||
|
|
## 🧪 测试验证
|
|||
|
|
|
|||
|
|
### 验证步骤
|
|||
|
|
|
|||
|
|
1. **查看 systemd 配置**后,运行测试:
|
|||
|
|
- 如果有 20 分钟限制 → 移除后测试能否运行超过 20 分钟
|
|||
|
|
- 如果没有限制 → 继续其他方案
|
|||
|
|
|
|||
|
|
2. **启用 coredump** 后,等待下次崩溃:
|
|||
|
|
- 查看是否生成了 coredump 文件
|
|||
|
|
- 使用 gdb 分析崩溃点
|
|||
|
|
|
|||
|
|
3. **增加信号处理器** 后,查看日志:
|
|||
|
|
- 如果看到 "SIGNAL XX RECEIVED",说明是信号导致
|
|||
|
|
- 根据信号类型判断原因
|
|||
|
|
|
|||
|
|
## 📈 下一步行动
|
|||
|
|
|
|||
|
|
**请先执行以下命令并提供输出**:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. 查看 systemd 服务完整配置
|
|||
|
|
sudo systemctl cat dronescrewserver.service
|
|||
|
|
|
|||
|
|
# 2. 查看服务超时相关属性
|
|||
|
|
sudo systemctl show dronescrewserver.service | grep -E "RuntimeMaxSec|WatchdogSec|TimeoutStopSec|TimeoutStartSec"
|
|||
|
|
|
|||
|
|
# 3. 查看最近的 systemd 日志(包含信号信息)
|
|||
|
|
sudo journalctl -u dronescrewserver.service --since "2 hours ago" | tail -100
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
根据这些信息,我们就能确定是否是 systemd 配置问题,然后针对性解决。
|
|||
|
|
|
|||
|
|
## 📝 修改记录
|
|||
|
|
|
|||
|
|
| 日期 | 问题 | 解决方案 | 状态 |
|
|||
|
|
|------|------|---------|------|
|
|||
|
|
| 2026-06-04 | PNG 编码崩溃 | 禁用 PNG 压缩 | ✅ 已修复 |
|
|||
|
|
| 2026-06-04 | 20 分钟定时崩溃 | 待确认 systemd 配置 | 🔍 调查中 |
|