想要快速判断 Linux 系统崩溃的大致方向,最直接的方法就是查看 /var/crash/ 最新子目录中 dmesg.* 文件的最后 50 行。这里通常最容易暴露 kernel panic 或 Oops 的关键信息,像“Kernel panic - not syncing”“Oops”“Call Trace:”这类关键词,基本一眼就能锁定排查重点。很多情况下,90% 的根本原因就藏在这几行日志里。

崩溃后怎么快速定位 panic 或 Oops 行?
先查看 /var/crash/ 下面最新的子目录中的 dmesg.* 文件,这通常就是 Linux 系统崩溃前内核保留下来的实时日志快照。先不要急着使用 crash 工具,很多时候最有价值的故障线索,往往就集中在最后几十行里,比如 Kernel panic - not syncing、Oops、Call Trace: 这些核心提示信息。
执行:cat /var/crash/$(ls -t /var/crash | head -n1)/dmesg.* | tail -n 50
- 如果看到
BUG: unable to handle kernel NULL pointer dereference这类报错,通常说明发生了空指针解引用,可以直接继续查找Call Trace:后面的函数调用链 IP:后面的地址表示异常指令位置,SP:表示当前栈顶地址,这两个关键值后续在使用crash分析内核堆栈时会派上用场- 还要注意时间戳是否连续——有些系统在 panic 前会卡顿几秒,如果
dmesg尾部时间跳变过大,往往说明日志可能被截断,这时需要结合journalctl -b -1补充查看上一次启动的日志
crash 工具里怎么看进程级堆栈?
crash 并不是普通的日志查看工具,它是专门用于解析 vmcore 内存转储镜像的交互式调试器。要正常分析 Linux 崩溃堆栈,必须满足两个前提:拥有对应内核版本的 vmlinux 符号文件,并且正确加载了对应的 dump.XXXX 文件。
进入崩溃目录后,运行:crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux dump.XXXX
- 进入交互界面后,先执行
bt——这是最常用的命令,用来显示当前 CPU 上崩溃线程的完整调用栈,包括函数名、偏移量以及源码行号(如果已安装 debuginfo) - 如果
bt输出中全是十六进制地址,没有函数名,通常说明vmlinux路径不正确,或者 debuginfo 包没有安装完整;可以通过find /usr/lib/debug -name vmlinux 2>/dev/null查找实际路径 - 如果想查看指定进程(例如 PID=1234)的堆栈,可使用
bt 1234;如果要查看所有 CPU 的调用栈,则使用bt -a
没 kdump 怎么临时抓内核堆栈?
如果系统还在运行,但已经出现异常现象(例如软锁死、响应延迟高),同时又没有配置 kdump,那么可以借助 SysRq 触发即时内核堆栈打印。前提是 /proc/sys/kernel/sysrq 的值为 1(多数 Linux 发行版默认开启)。
物理机或带控制台的虚拟机上操作:
按住 Alt + SysRq(即 Print Screen 键),松开后立刻按 t(小写)
- 输出内容会写入
dmesg缓冲区,此时应立即执行dmesg | tail -n 100查看,里面通常会包含每个 CPU 的Call Trace:信息 - 需要注意:这个操作不会自动保存到磁盘,只会暂存在内存日志中,系统一旦重启就会丢失;如果系统已经完全无响应,
SysRq也可能失效 - 某些云服务器或容器环境默认禁用了
SysRq,可先执行cat /proc/sys/kernel/sysrq检查返回值;如果不是 1,就需要先执行echo 1 > /proc/sys/kernel/sysrq(需要 root 权限)
用户态程序崩溃的堆栈在哪找?
内核崩溃和用户态程序崩溃属于两套完全不同的机制。像 nginx、Python 脚本这类用户态程序发生崩溃时,主要依赖的是 core dump,而不是 vmcore。
确认 core 生成已开启:ulimit -c 必须非 0(推荐 ulimit -c unlimited);sysctl kernel.core_pattern 查看生成路径,常见配置如 core.%e.%p 或 /var/lib/core/core.%e.%p
- 找到 core 文件后,可使用
gdb ./your_program core.xxx,然后执行bt查看用户态程序的调用堆栈 - 如果
bt显示大量??,通常说明编译时没有加入-g,或者符号信息已被 strip;生产环境的 release 版本建议保留.debug段,或单独保存符号文件 addr2line -e ./your_program -f -C 0x7f8b12345678可以把任意地址转换为对应函数和代码行号,前提是二进制文件中包含调试信息
真正复杂的往往不是“如何查看堆栈”,而是堆栈信息中同时混杂了内核态和用户态上下文——例如程序在系统调用进入内核后发生 panic,这种情况下需要先用 crash 分析内核栈,再结合 gdb 和对应 core 文件查看用户态现场。由于两者地址空间完全独立,因此不能直接交叉解析。
