性能分析工具入门:Linux perf、火焰图、strace、top/htop 的基本使用
性能优化这件事,说白了就是先找到瓶颈在哪,再动手改代码。但很多新手一上来就盯着代码看,觉得「我这段逻辑写得挺好啊」。嗯,我当年也这么干过,结果调了一整天,发现是系统调用太频繁了。
所以这一章,咱们先不急着优化。先把工具箱里的几把「扳手」认全了。你想想看,连问题在哪都不知道,怎么修?
1. top / htop:看一眼就知道谁在吃资源
这是最基础的命令,也是我每次排查问题的第一站。登录服务器,先敲个 top,看看 CPU 和内存的「大盘」。
top 的核心字段
| 字段 | 含义 | 我关注的点 |
|---|---|---|
| %CPU | 进程 CPU 使用率 | 超过 100% 说明是多线程在跑 |
| %MEM | 进程内存占比 | 单个进程吃太多,可能有泄漏 |
| RES | 常驻内存(单位 KB) | 这个才是实际占用的物理内存 |
| S | 进程状态 | R 运行,S 睡眠,D 不可中断 |
| TIME+ | 累计 CPU 时间 | 跑了几小时的进程,TIME+ 会很大 |
P 按 CPU 排序,按 M 按内存排序。我习惯先按 P 看一眼,再按 M 确认一下。
htop 是 top 的增强版。颜色更直观,支持鼠标操作,还能直接看到进程树。我个人更推荐 htop,尤其是当你需要频繁切换排序时。
# 安装 htop
sudo apt install htop # Ubuntu/Debian
sudo yum install htop # CentOS/RHEL
# 直接运行
htop
在 htop 里,你可以用 F6 选择排序字段,F9 直接杀进程。嗯,比 top 方便不少。
top -b -n 2 -d 1 采集两秒的数据,或者用 htop 的延时模式。
2. strace:追踪系统调用的「显微镜」
有时候进程 CPU 不高,但就是慢。这时候我通常会怀疑:是不是系统调用太多了?
strace 就是干这个的。它能记录进程发起的每一次系统调用,包括参数和返回值。
# 追踪一个正在运行的进程(PID 为 1234)
strace -p 1234
# 追踪新启动的命令
strace -o output.log ls -l
# 只看特定的系统调用(比如 read/write)
strace -e trace=read,write -p 1234
我曾经遇到过一个线上问题:一个 Java 服务每隔几秒就卡顿一下。用 strace 一追,发现它在频繁调用 gettimeofday,每秒几千次。后来查代码,是某个日志框架在每次写日志时都取了一次时间戳。去掉之后,性能直接翻倍。
-c 参数做统计,看看哪个系统调用耗时最长。
# 统计系统调用耗时
strace -c -p 1234
# 输出示例
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
45.23 0.123456 12.34 10000 read
30.12 0.087654 8.76 10000 write
15.45 0.045678 4.56 10000 gettimeofday
...
看到没?gettimeofday 占了 15% 的时间。这就是线索。
-p 只 attach 几秒钟。
3. Linux perf:CPU 性能分析的「核武器」
top 告诉你哪个进程吃 CPU,strace 告诉你系统调用慢。但如果你想知道「CPU 到底在忙什么」,那就得上 perf 了。
perf 是 Linux 内核自带的性能分析工具。它能采样 CPU 的指令指针,告诉你代码的哪些行、哪些函数占用了最多的 CPU 时间。
perf 的基本用法
# 采样一个正在运行的进程(PID 1234),持续 10 秒
perf record -p 1234 -g -- sleep 10
# 生成报告
perf report
# 只看调用链
perf report --stdio -g
-g 参数是关键。它开启调用链采样,这样你就能看到「谁调了谁」。我见过很多团队只采样不记录调用链,结果看到一个热点函数叫 do_work,但不知道是谁调进来的,等于白干。
perf top 看一眼热点,再决定要不要 perf record。perf top 是实时显示的,不用等。
# 实时查看 CPU 热点
perf top -p 1234
perf 的输出里,你会看到类似这样的内容:
Samples: 1K of event 'cycles', Event count (approx.): 123456789
Overhead Shared Object Symbol
25.12% libc-2.31.so [.] __memcpy_avx_unaligned
15.45% myapp [.] process_request
10.23% [kernel] [k] do_syscall_64
...
看到 __memcpy_avx_unaligned 占 25%?说明你的程序在大量拷贝内存。这时候就该想想:能不能减少拷贝?能不能用零拷贝技术?
4. 火焰图:让性能瓶颈「一目了然」
perf report 的输出是文本的,看久了眼睛疼。火焰图(Flame Graph)是 Brendan Gregg 发明的可视化工具,把 perf 的采样数据变成一张 SVG 图。
火焰图长什么样?
- X 轴:采样数量(不是时间),越宽的函数占 CPU 越多。
- Y 轴:调用栈深度,越往上越深。
- 颜色:通常橙色是用户态,蓝色是内核态。
怎么看?找「平顶山」——就是那些顶部很宽的函数。它们就是 CPU 的热点。
生成火焰图的步骤
# 1. 用 perf 采集数据
perf record -p 1234 -g -- sleep 30
# 2. 生成火焰图(需要 FlameGraph 工具)
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph
# 3. 转换 perf 数据
perf script -i ../perf.data | ./stackcollapse-perf.pl > out.perf-folded
# 4. 生成 SVG
./flamegraph.pl out.perf-folded > flame.svg
# 5. 用浏览器打开 flame.svg
我曾经帮一个团队排查 Node.js 服务的性能问题。他们觉得是数据库慢,结果火焰图一看,40% 的 CPU 花在 JSON 序列化上。后来换了更快的序列化库,QPS 直接翻倍。
5. 知识体系:这些工具怎么配合?
工具多了,容易乱。我画了一张图,帮你理清思路。
这张图的核心逻辑很简单:
- 先看大盘:用 top/htop 确认是 CPU、内存还是 IO 的问题。
- CPU 高:上 perf 采样,生成火焰图,找热点函数。
- 进程卡顿:用 strace 追踪系统调用,看是不是频繁 IO 或锁等待。
- 内存/IO 异常:top 看内存,perf 看内核态,结合分析。
6. 避坑指南:新手最容易犯的错
- 在线上直接 strace 高并发进程:strace 会让进程慢 10-100 倍。我一般用
-pattach 几秒,或者先抓 perf 数据。 - perf record 不设时长:默认会一直跑,直到你 Ctrl+C。建议加
-- sleep 10限制时间。 - 火焰图不看 Y 轴:只看 X 轴宽度,忽略调用栈深度。其实 Y 轴能告诉你「这个函数是被谁调进来的」。
- 只看用户态,不看内核态:很多性能瓶颈在内核,比如文件系统、网络栈。perf 默认采样用户态,记得加
-k或--all-user参数。
perf-map-agent 或者用 -g 参数。