内核死锁分析核心是定位d状态线程并回溯等待链确认循环等待闭环;需用ps筛选d态进程/线程,解析/proc/pid/stack或crash bt查看调用栈,从中提取锁地址并查持锁者,结合lockdep日志快速识别闭环。

分析内核死锁时的堆栈信息,核心是定位处于不可中断睡眠(D 状态)的线程,并沿着其等待链回溯锁持有者,最终确认循环等待闭环。关键不在于看“谁卡住了”,而在于搞清“谁在等谁的锁”。
快速识别可疑线程
死锁发生时,至少有两个线程会陷入 D 状态,无法被信号中断或调度。用以下命令筛选:
- ps -eo pid,comm,wchan:20,state,ppid | awk '$4=="D" {print}' —— 查看 D 状态进程及其等待的内核函数(wchan)
- ps -eLo pid,tid,comm,state,wtchan | grep ' D ' —— 更细粒度显示线程级等待点,尤其适合多线程场景
重点关注 watchdog、kthreadd、system_server(Android)等关键线程是否卡在 down_read、mutex_lock、__lock_acquire 等锁相关函数上。
提取并解析调用栈
对每个 D 状态线程,需获取其完整内核调用栈:
- 若系统可访问:cat /proc/PID/stack 直接读取当前栈;注意 PID 是线程 ID(LWP),不是进程 ID
- 若系统已挂死或需离线分析:依赖 ramdump + crash 工具,运行 crash> bt -v
查看寄存器和符号化栈帧 - 栈中重点找锁操作上下文,例如 proc_pid_cmdline_read → down_read(&mm->mmap_sem),说明该线程正等待某进程的内存映射读锁
定位锁持有者
从等待线程的栈中推导出被等待锁的地址,再查谁持有它:
- 在 down_read 调用附近查看寄存器(如 x0、x21、x28),结合结构体偏移(如 mm_struct 的 mmap_sem 偏移为 0x68)反推出锁实例地址
- 用 crash> sym
或 crash> struct rw_semaphore 查看该锁的 owner 字段,得到持锁线程 PID - 再查该 PID 的栈,确认它是否也在等待另一个锁——若它等待的目标恰好由前一线程持有,就构成闭环
借助 lockdep 自动检测
若内核启用了 CONFIG_LOCKDEP=y,死锁触发时通常会直接打印警告:
- 执行 dmesg | grep -i "circular\|recursive\|deadlock",搜索关键词如 “circular locking dependency”
- 输出中会明确列出两个冲突锁类、各自加锁顺序、以及完整调用路径,无需手动回溯
- 即使未 panic,也可通过 cat /proc/lockdep_chains 查看累积的锁依赖关系,提前发现风险模式











