6.7 KiB
6.7 KiB
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
🔍 关键线索
-
时间规律性:
- 两次崩溃都在启动后约 19-20 分钟
- 与是否运行检测无关
- 与处理的帧数无关
-
Idle 模式也崩溃:
- 程序完全空载(没有检测、没有图像处理)
- 仅运行心跳日志
- 说明不是业务逻辑代码的问题
-
没有异常日志:
- 所有 try-catch 都没有捕获到异常
- 所有业务流程日志都完整
- 崩溃发生在代码逻辑之外
💡 根本原因推断
最可能的原因:systemd 看门狗或超时配置
证据:
- 精确的 20 分钟间隔:不像随机崩溃,更像超时强制终止
- 退出码 255:异常退出,但非段错误(段错误通常是 139)
- systemd 日志:
Main process exited, code=exited, status=255/EXCEPTION - Idle 也崩溃:排除了所有业务代码问题
systemd 可能的配置:
[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 服务配置(优先)
步骤:
# 查看当前服务配置
sudo systemctl cat dronescrewserver.service
# 查看完整状态
sudo systemctl status dronescrewserver.service
# 查看服务属性
sudo systemctl show dronescrewserver.service | grep -i "timeout\|watchdog\|runtime"
如果发现超时配置,修改服务文件:
[Service]
# 移除或增加运行时间限制
# RuntimeMaxSec=infinity # 或设置更长时间
# WatchdogSec=0 # 禁用看门狗
# 增加停止超时(避免强制杀死)
TimeoutStopSec=30s
# 重启策略
Restart=always
RestartSec=5s
应用配置:
sudo systemctl daemon-reload
sudo systemctl restart dronescrewserver
方案 2:启用 coredump 定位段错误(如果是段错误)
# 启用 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:增加详细的系统调用跟踪
# 使用 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 中增加信号处理,捕获崩溃信号:
#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)
-
检查 systemd 服务配置
sudo systemctl show dronescrewserver.service | grep -i "timeout\|watchdog\|runtime" -
查看完整的 systemd 日志
sudo journalctl -u dronescrewserver.service --since "1 hour ago" | grep -i "timeout\|killed\|signal"
短期(优先级 P1)
- 启用 coredump(如果是段错误)
- 增加信号处理器(捕获终止信号)
中期(优先级 P2)
- 代码审查:
- 检查是否有死锁可能
- 检查线程退出逻辑
- 检查资源清理
🧪 测试验证
验证步骤
-
查看 systemd 配置后,运行测试:
- 如果有 20 分钟限制 → 移除后测试能否运行超过 20 分钟
- 如果没有限制 → 继续其他方案
-
启用 coredump 后,等待下次崩溃:
- 查看是否生成了 coredump 文件
- 使用 gdb 分析崩溃点
-
增加信号处理器 后,查看日志:
- 如果看到 "SIGNAL XX RECEIVED",说明是信号导致
- 根据信号类型判断原因
📈 下一步行动
请先执行以下命令并提供输出:
# 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 配置 | 🔍 调查中 |