top与perf配合可定位cpu飙升根因:top锁定高cpu进程,perf record采集热点函数,perf report或火焰图分析耗时代码,再依模式(如锁竞争、内存分配)针对性优化。

当Linux系统出现CPU使用率飙升时,单靠top只能看到哪个进程在“吃”CPU,但无法知道它到底在执行什么代码——是死循环?锁竞争?还是频繁的系统调用?这时需要perf深入函数级甚至指令级分析,top与perf配合,才能快速定位根因。
用top快速锁定高CPU进程
top是第一道筛子,重点看几个字段:
- PID:进程唯一标识,后续perf采样要用
-
%CPU:按实际占用率排序(按
P键),持续高于80%且不回落的进程需重点关注 - COMMAND:确认是不是业务关键进程(如java、nginx、python),避免误杀系统守护进程
- TIME+:累计CPU时间,若增长极快,说明该进程近期活跃度异常升高
注意:top默认刷新间隔是3秒,可按s键改为1秒或0.5秒,便于捕捉瞬时尖峰;按H可切换线程视图,确认是否某个线程独占CPU。
用perf record抓取热点函数
拿到可疑PID后,立即用perf record采集栈信息,推荐以下命令:
perf record -g -p <PID> -a -- sleep 10
-
-g:开启调用图(call graph),能看清函数调用链,比如
main → handle_request → json_parse → memcpy -
-p:指定进程PID;加
-a可同时捕获其所有线程(含内核线程) - -- sleep 10:让perf运行10秒后自动停止,避免手动中断导致采样不完整
若进程启动不久就飙高,也可用perf record -g -e cpu-clock:u只采用户态,减少干扰;对Java应用,建议加上-F 99(采样频率99Hz),避免过度开销。
用perf report分析火焰图式热点
执行perf report -g --no-children进入交互式报告:
- 按
Enter展开某函数,查看它调用了哪些下层函数 - 关注“Self”列占比高的函数——这是真正耗CPU的源头,不是被调用的“背锅侠”
- 若看到大量
[unknown]或__libc_start_main,说明缺少符号表,需安装对应debuginfo包(如debuginfo-install glibc)或用perf buildid-list核对二进制版本
更直观的方式是生成火焰图:perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > cpu.svg,打开SVG文件,宽底座的函数就是罪魁祸首。
常见模式与对应动作
根据perf结果,可快速归类处理:
- 集中在某个业务函数(如process_order):检查该函数是否有未优化的循环、重复序列化、或阻塞式IO混在计算逻辑中
- 大量出现在malloc/free或jemalloc内部:内存分配频繁,考虑对象池复用、减少临时对象创建
-
停在futex_wait、pthread_mutex_lock等同步原语:存在锁竞争,用
perf lock record进一步分析锁持有时间 - 大量sys_write、sys_read、epoll_wait:I/O密集型,但CPU高说明可能在用户态反复拷贝数据(如小包频繁read/write),应检查缓冲区大小和零拷贝配置
perf不会直接告诉你“怎么改代码”,但它会精准指出“哪一行附近最热”。结合源码和上下文,修复方向就很清晰了。










