Linux 性能观测与调试命令速查
更新时间:2026-08-28。本文是 Linux 命令速查主题第⑨族:性能观测与调试,约 28 个命令。这一族是排查"为什么慢"的主力——
top只能告诉你"CPU 高了",而这族命令能告诉你"高在哪一行代码、哪次系统调用、哪块内存"。深入用法见 perf 火焰图,原理见 CPU 微架构。
一、性能剖析:perf 全家桶
perf(Performance Counters for Linux,Linux 性能计数器子系统)是内核自带的性能剖析工具,能直接读取 CPU 的硬件计数器(PMU,Performance Monitoring Unit,性能监控单元),采样开销远低于插桩类工具。日常排查 80% 的"CPU 高"问题,用 perf top 和 perf record 两招就能定位到函数。
| 命令 | 作用 | 常用示例 |
|---|---|---|
perf | Linux 官方性能剖析器,基于硬件计数器采样,可看热点函数、调用链、缓存命中率、缺页等 | perf top(实时热点);perf record -F 99 -g -p PID(按 99Hz 采样并抓调用栈);perf report(查看报告) |
perf stat | 汇总执行期间的计数器总量,如指令数、IPC、缓存命中率、分支预测失败率 | perf stat -e cycles,instructions,cache-misses ./app |
perf top | 实时显示占用 CPU 最多的函数,类似 top 但精确到符号级别而不是进程级别 | perf top -g(带调用链);perf top -p 1234(只看某进程) |
perf record | 采样并记录到 perf.data,供离线分析;-g 抓调用栈是生成火焰图的前提 | perf record -F 99 -g -- sleep 30;perf record -e page-faults -a(全系统缺页) |
perf report | 读取 perf.data 生成交互式报告,可逐层展开调用栈定位热点 | perf report --stdio(非交互);perf report -g graph(调用图) |
perf list | 列出当前 CPU 支持的所有性能事件,不确定事件名时先查它 | `perf list |
perf annotate | 把热点反汇编到源码行级,精确到哪条指令耗时最多 | perf annotate -s func_name |
采样频率的经验值:
-F 99是社区常用值——99Hz 足够低的开销,又不会与常见定时器频率(100Hz)产生采样共振导致偏差。想抓短时尖峰可以提到-F 999,但生产环境别长期跑。
二、系统调用与库调用跟踪
strace(system call trace,系统调用跟踪)通过内核的 ptrace 机制拦截进程的系统调用,是"进程卡在哪"的第一现场工具。它慢(每个系统调用两次陷入),但对低频、卡死、启动失败类问题无可替代。ltrace 跟踪的是库函数调用,比 strace 更靠近用户态。
| 命令 | 作用 | 常用示例 |
|---|---|---|
strace | 跟踪进程的系统调用与信号,可看参数、返回值、耗时,定位卡死/失败原因 | strace -p 1234(附着进程);strace -c(统计各调用耗时占比);strace -T -tt(打印时间戳与耗时);strace -e trace=file(只看文件类调用) |
strace -f | 同时跟踪子进程与线程,多线程/多进程程序必须加,否则会漏掉大部分调用 | strace -f -p 1234;strace -ff -o trace.log ./app(每个进程单独文件) |
ltrace | 跟踪用户态库函数调用(malloc、strlen 等),粒度比 strace 更靠近应用逻辑 | ltrace -c ./app(统计库调用次数与耗时);ltrace -e malloc+free ./app |
strace会让目标进程变慢一个数量级,不要在生产高负载进程上长时间挂着。想低开销地看系统调用频率,用perf trace或直接读/proc/PID/syscall。深入案例见 strace 排障实战。
三、二进制与符号分析
线上进程崩了、符号对不上、想知道某个函数到底被编译成什么样——这族命令用来对付"没有源码"或"源码与二进制不一致"的场景。ELF(Executable and Linkable Format,可执行与可链接格式)是 Linux 上可执行文件与目标文件的标准格式,下面几个命令本质都是 ELF 格式的解析器。
| 命令 | 作用 | 常用示例 |
|---|---|---|
gdb | GNU 调试器,可断点、单步、查看变量与内存、分析 core dump,是定位崩溃与逻辑错误的终极手段 | gdb -p 1234(附着);gdb ./app core.1234(分析 core);bt(打印调用栈);info threads(看线程) |
objdump | 反汇编二进制,查看段、符号、重定位信息,验证编译器优化效果常用 | objdump -d ./app(反汇编);objdump -S(源码与汇编对照,需 -g 编译);objdump -h(段头) |
readelf | 读取 ELF 文件头、程序头、节头、动态段等元信息,判架构/依赖/是否 stripped | readelf -h ./app(文件头);readelf -d ./app(动态依赖);readelf -S(节头表) |
nm | 列出目标文件的符号表,查函数/变量是否被导出、是否有未解析符号 | nm -C ./app(C++ 符号还原,去 name mangling);nm -u(只列未定义符号) |
ldd | 列出可执行文件依赖的共享库及其解析路径,排查"找不到 so" | ldd ./app;`ldd ./app |
ldconfig | 重建共享库缓存 /etc/ld.so.cache,新增或移动 .so 后需要执行 | sudo ldconfig;`ldconfig -p |
addr2line | 把崩溃日志里的地址翻译成"文件:行号",分析内核 oops 或崩溃栈必备 | addr2line -e ./app -f -C 0x4005b6 |
c++filt | 还原 C++ 编译后的重整符号(mangled name),把 _Z3fooi 变回 foo(int) | c++filt _Z3fooi |
四、内存映射与栈
| 命令 | 作用 | 常用示例 |
|---|---|---|
pmap | 显示进程的内存映射布局与每段占用,定位内存异常增长、匿名映射泄漏 | pmap -x 1234(详细);pmap -XX(含内核页表信息) |
pstack | 打印进程所有线程的调用栈(GNU 版基于 gdb),快速看线程卡在哪 | pstack 1234 |
eu-stack | elfutils 提供的栈回溯工具,比 pstack 快很多,对运行中进程影响小,适合频繁采样 | eu-stack -p 1234 |
想看进程连打多次栈(判断是真死循环还是刚好在忙),用
for i in $(seq 10); do eu-stack -p PID; sleep 1; done。如果十次栈都一样,基本就是卡住了。内存整体口径见 free 命令,缺页与换页见 vmstat。
五、磁盘与 I/O 观测
CPU 高的另一半原因往往是等 I/O。这族命令看的是"设备忙不忙、等不等、谁在等",与 CPU 侧的 perf 互补——先确认瓶颈在 I/O 再深入,能省掉大量无用剖析。
| 命令 | 作用 | 常用示例 |
|---|---|---|
iostat | 报告 CPU 与磁盘 I/O 统计,%util 接近 100% 说明设备饱和,await 高说明请求排队 | iostat -x 1(扩展统计,每秒刷新);iostat -x -d sda 1(只看某盘) |
sar | 系统活动报告,能回看历史数据(依赖 sysstat 采集),排查"昨晚三点发生了什么" | sar -d 1 3(磁盘);sar -r(内存);sar -n DEV 1(网络);sar -f /var/log/sa/sa27(读历史) |
pidstat | 按进程/线程统计 CPU、内存、I/O、上下文切换,定位到具体是哪个进程在搞事 | pidstat -u 1(CPU);pidstat -d 1(I/O);pidstat -w 1(上下文切换);pidstat -t -p PID 1(线程级) |
iotop | 类似 top 的实时 I/O 视图,按进程排序读写速率 | iotop -o(只显示有 I/O 的进程);iotop -p 1234 |
dstat | 综合 CPU/磁盘/网络/内存/系统的多列实时统计,一屏看全貌 | dstat -cdngy 1;dstat --top-io --top-cpu |
slabtop | 实时显示内核 slab 缓存占用,排查内核对象(dentry、inode)耗尽 | slabtop -o(非交互输出一次) |
判读要点:
%util高但await不高,说明设备吞吐被打满但响应还行;await飙升说明队列积压,通常伴随avgqu-sz增大。详细指标含义见 iostat 详解 与 sar 历史回溯。
六、NUMA 与 CPU 亲和
NUMA(Non-Uniform Memory Access,非统一内存访问)架构下,CPU 访问本地内存比访问远端内存快得多。数据库、高频交易这类对延迟敏感的服务,跨 NUMA 访存是常见的隐性性能杀手——看起来 CPU 和内存都够用,延迟却莫名偏高。
| 命令 | 作用 | 常用示例 |
|---|---|---|
numastat | 显示各 NUMA 节点的内存分配与命中统计,numa_miss 高说明跨节点访问严重 | numastat;numastat -p 1234(看某进程) |
numactl | 控制进程或共享内存的 NUMA 策略,把进程绑到指定节点以消除跨节点访存 | numactl --cpunodebind=0 --membind=0 ./app;numactl -H(查看拓扑) |
taskset | 绑定进程到指定 CPU 核心,减少缓存失效与上下文切换抖动 | taskset -c 0-3 ./app(绑到 0~3 核);taskset -cp 0 1234(改运行中进程) |
turbostat | 读取 CPU 频率、C-state、温度、功耗,排查降频导致的"突然变慢" | turbostat --interval 5 |
绑核不是万能药:绑得太死会让其他进程抢不到 CPU,反而制造瓶颈。一般只在确认了跨节点/跨核抖动代价后才做。实测方法与数据见 numactl 实验。
七、动态追踪
前面几族的采样点都是固定的(函数、系统调用、计数器),而 eBPF(extended Berkeley Packet Filter,扩展伯克利包过滤器)允许你在内核里安全地运行自定义程序,想看什么事件就挂钩子,几乎无开销地回答任意问题。这是现代 Linux 可观测性的分水岭。
| 命令 | 作用 | 常用示例 |
|---|---|---|
bpftrace | eBPF 的高级追踪语言,一行命令即可统计内核/用户态事件,适合临时探查 | bpftrace -e 'tracepoint:syscalls:sys_enter_openat { @[comm] = count(); }';bpftrace -l(列出可挂的点) |
sysdig | 以系统调用为数据源的系统级排查工具,带丰富的现成脚本(chisel) | sysdig -c topprocs_cpu;sysdig proc.name=nginx(按条件过滤) |
systemtap | 老牌内核动态追踪框架,功能强但需编译内核模块,新系统一般优先 eBPF | stap -e 'probe syscall.open { log(execname()) }' |
八、资源限制与 cgroup
cgroup(control group,控制组)是内核提供的资源限制与统计机制,容器(Docker、Kubernetes)的资源限制就是基于它实现的。这族命令用来查看和设置进程能用多少 CPU、内存、I/O。
| 命令 | 作用 | 常用示例 |
|---|---|---|
ulimit | 设置当前 shell 及其子进程的资源上限(文件数、栈大小、core 大小等) | ulimit -n(查看文件描述符上限);ulimit -n 65535(临时调高);ulimit -c unlimited(允许生成 core) |
prlimit | 查看或修改运行中进程的资源限制,弥补 ulimit 只能改自身的不足 | prlimit --pid 1234 --nofile=65535:65535 |
systemd-cgtop | 按 cgroup 实时显示资源占用,看容器/服务实际用了多少 | systemd-cgtop --order=memory |
setsid | 让进程脱离当前终端会话独立运行,比 nohup 更彻底(完全脱离控制终端) | setsid ./app > app.log 2>&1 < /dev/null & |
ulimit -n太小是线上最常见的事故之一——"too many open files"几乎都源于此。注意ulimit改的是当前 shell,永久生效要改/etc/security/limits.conf,systemd 服务则要在 unit 里写LimitNOFILE=。文件描述符的完整链路见 ulimit 实验。
一句话总结
性能观测速查:先 top/pidstat 确认是谁在烧资源,perf top/perf record 定位到热点函数,strace 查卡在哪个系统调用,iostat/iotop 排除 I/O 瓶颈,numastat/taskset 查 NUMA 与绑核,bpftrace 兜底回答任意问题——28 个命令串起来,就是从"感觉慢"到"知道慢在哪一行"的完整路径。