GrabBag/App/DroneScrewbolt/CRASH_20MIN_TIMEOUT_ANALYSIS.md

260 lines
6.7 KiB
Markdown
Raw Normal View History

2026-06-26 17:55:15 +08:00
# DroneScrewServer 崩溃根因最终分析
## 🎯 最新发现2026-06-04
### 崩溃模式确认
经过多次测试和日志分析,发现了以下关键信息:
#### 测试 1PNG 编码崩溃(已解决)
- **崩溃点**`[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 配置 | 🔍 调查中 |