# 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 #include 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 配置 | 🔍 调查中 |