29、常见故障排除:启动失败修复、驱动冲突解决、内存泄漏定位、日志分析技巧
说实话,做 Jetson 开发最头疼的不是写代码,而是系统突然起不来了。我见过太多同事,板子一黑屏就慌了,直接重刷系统。其实很多问题,咱们冷静分析一下,完全能救回来。
这一章,我就把这几年来踩过的坑、修过的板子,总结成一套实战方法。从启动失败到内存泄漏,咱们一个一个来。
29.1 启动失败修复:三板斧
启动失败,说白了就是系统在开机过程中卡住了。我遇到过最夸张的一次,客户说板子点不亮,结果只是 HDMI 线松了。嗯,先排除这种低级问题。
29.1.1 第一板斧:检查电源和指示灯
Jetson 板子通电后,LED 灯会按特定模式闪烁。比如 Orin NX 正常启动时,绿色 LED 会先快闪,然后慢闪。如果灯不亮,或者一直快闪不停,那就是有问题。
- LED 不亮: 检查电源适配器,至少 15V/3A 以上。我见过有人用手机充电器去带 Orin,那肯定不行。
- LED 快闪不停: 通常是 bootloader 损坏,或者 SD 卡/SSD 接触不良。
- LED 常亮但无显示: 可能是显示驱动问题,或者系统卡在了内核加载阶段。
29.1.2 第二板斧:进入恢复模式
如果系统完全起不来,可以试试强制进入恢复模式(Force Recovery Mode, FRM)。
# 以 Jetson Orin NX 为例
# 1. 按住 FORCE RECOVERY 按钮
# 2. 按住 RESET 按钮
# 3. 松开 RESET,保持 FORCE RECOVERY 2秒后松开
# 4. 连接主机,检查是否识别到设备
lsusb | grep NVIDIA
# 应该看到:ID 0955:7023 NVIDIA Corp.
进入恢复模式后,就可以用 flash.sh 重新烧录系统了。但别急着烧,先试试能不能救活。
29.1.3 第三板斧:修复 bootloader
很多时候,启动失败是因为 bootloader 的配置文件坏了。比如你改了 extlinux.conf,结果语法写错了。
# 进入恢复模式后,挂载 SD 卡或 eMMC
sudo ./flash.sh -r -k APP jetson-orin-nano-devkit mmcblk0p1
# 或者只更新 bootloader 分区
sudo ./flash.sh -r -k kernel-dtb jetson-orin-nano-devkit mmcblk0p1
29.2 驱动冲突解决:谁动了我的内核?
驱动冲突,是 Jetson 上最常见的问题之一。尤其是当你装了多个版本的 JetPack,或者自己编译了内核模块。
我记得有一次,客户在 Orin NX 上同时装了 JetPack 5.1 和 6.0 的库,结果摄像头驱动死活加载不了。查了半天,发现是 libcuda.so 的版本冲突了。
29.2.1 如何检测驱动冲突
最简单的方法,看 dmesg 日志。驱动加载失败时,内核会告诉你原因。
# 查看内核日志,过滤驱动相关
dmesg | grep -i "failed\|error\|conflict"
# 查看已加载的模块
lsmod | sort
# 检查模块依赖
modinfo nvgpu | grep depends
如果看到类似 nvgpu: disagrees about version of symbol module_layout 这样的错误,那就是内核版本不匹配。
29.2.2 解决冲突的步骤
- 确认内核版本:
uname -r,看看当前跑的内核是哪个。 - 检查模块路径:
/lib/modules/$(uname -r)/下有没有对应的 .ko 文件。 - 手动加载模块:
sudo insmod /path/to/module.ko,看报错信息。 - 卸载冲突模块:
sudo modprobe -r nvgpu,再重新加载。
29.3 内存泄漏定位:谁吃了我的内存?
内存泄漏,是嵌入式开发的老大难问题。Jetson 上跑 AI 模型,动不动就几百 MB 显存,泄漏起来特别快。
我遇到过最离谱的一次,一个客户写的推理程序,每跑一次就泄漏 50MB 显存。跑了 100 次后,系统直接 OOM,连 SSH 都连不上了。
29.3.1 用工具定位泄漏
我个人最常用的工具是 valgrind 和 nvidia-smi 配合使用。
# 查看显存使用情况
watch -n 1 nvidia-smi
# 用 valgrind 检测内存泄漏
valgrind --leak-check=full --show-leak-kinds=all ./your_program
# 如果是 Python 程序,用 tracemalloc
python -m tracemalloc your_script.py
但 valgrind 在 Jetson 上跑起来很慢,尤其是跑神经网络的时候。所以我一般先用 nvidia-smi 看显存趋势,确认有泄漏后,再用 valgrind 去定位具体代码。
29.3.2 手动排查技巧
有时候工具不好使,就得靠经验了。我总结了一套手动排查流程:
- 看 /proc/meminfo:
cat /proc/meminfo | grep -E "MemTotal|MemFree|Cached" - 看进程内存:
top -o %MEM或者htop - 看 slab 缓存:
cat /proc/slabinfo,有时候是内核模块泄漏了。 - 用 smem 看 USS/PSS:
smem -t -p,这个能看出进程实际占用的物理内存。
av_frame_free() 没调用。说白了,就是申请了资源忘了释放。所以写代码时,一定要养成「谁申请,谁释放」的习惯。
29.4 日志分析技巧:从日志里读出真相
日志是系统给你的「遗言」。学会看日志,你就成功了一半。
29.4.1 关键日志文件
| 日志文件 | 用途 | 我的经验 |
|---|---|---|
| /var/log/syslog | 系统通用日志 | 启动失败先看这个,关键词搜 "error" |
| /var/log/kern.log | 内核日志 | 驱动问题、硬件错误都在这里 |
| /var/log/nv.log | NVIDIA 驱动日志 | CUDA、多媒体 API 的报错信息 |
| /var/log/daemon.log | 后台服务日志 | 比如 nvargus-daemon 的启动情况 |
29.4.2 高效分析日志的方法
别用 cat 看整个日志,那会累死你。用 grep 和 journalctl 配合。
# 只看最近 10 分钟的内核日志
journalctl -k --since "10 minutes ago"
# 按优先级过滤:只显示错误和警告
journalctl -p err -p warning
# 实时跟踪日志
tail -f /var/log/syslog | grep -E "error|failed|oom"
# 用 awk 统计错误出现次数
grep "error" /var/log/syslog | awk '{print $5}' | sort | uniq -c | sort -nr
嗯,这里有个小技巧。如果日志刷得特别快,比如摄像头驱动每秒报一堆错误,你可以先重定向到文件,再慢慢分析。
# 把日志抓下来,离线分析
journalctl -k -o short-precise > kernel_log.txt
# 然后用 vim 或者 less 慢慢看
29.4.3 常见日志模式解读
- "Out of memory: Killed process":OOM killer 出手了。说明内存不够,或者有泄漏。
- "NVRM: failed to register":NVIDIA 驱动注册失败。通常是内核版本不匹配。
- "tegra-i2c: timeout":I2C 总线超时。可能是硬件连接问题,或者设备地址冲突。
- "nvargus-daemon: Failed to open camera":摄像头初始化失败。检查 CSI 线缆和驱动。
29.5 知识体系总览
下面这张图,是我自己总结的故障排除流程。每次遇到问题,我就按这个思路走一遍,基本都能找到根因。
说白了,故障排除就是「看日志 → 定位 → 修复」的循环。别怕出问题,出一次问题,你就长一次经验。我刚开始做 Jetson 开发时,也是天天重刷系统。后来慢慢学会了看日志、分析问题,现在遇到问题反而有点兴奋——又能学新东西了。
嗯,这一章的内容就到这里。记住,工具是死的,思路是活的。把上面这些方法练熟了,你也能成为别人眼中的「Jetson 救火队员」。