Linux perf 命令:性能分析的瑞士军刀
perf 是 Linux 系统自带的性能分析工具,基于内核性能事件机制,可用于监控 CPU 使用率、缓存命中、函数调用开销、上下文切换等关键性能指标。它是排查程序性能瓶颈(如 CPU 密集、缓存失效、函数耗时过长)的核心工具,尤其适合分析 Java 等应用的底层运行情况。
perf 基本用法
命令格式
1 | perf [子命令] [选项] [目标程序/进程ID] |
perf 包含多个子命令,分别用于不同场景的性能分析,最常用的包括 stat(统计事件)、record(记录事件)、report(生成报告)等。
核心子命令
| 子命令 | 功能描述 |
|---|---|
perf stat |
统计指定事件(如 CPU 周期、缓存命中)的发生次数和频率,适合快速定位性能瓶颈。 |
perf record |
记录程序运行时的性能事件数据,生成二进制文件(默认 perf.data),用于后续分析。 |
perf report |
解析 perf record 生成的文件,展示函数级别的性能开销分布(如 CPU 占用率)。 |
perf top |
实时显示当前系统中消耗 CPU 最多的函数或指令,类似 top 但更深入。 |
常用场景与示例
perf stat:快速统计性能指标
perf stat 用于统计指定事件的发生情况,适合初步定位程序的性能特征(如是否 CPU 密集、缓存效率如何)。
基本用法
1 | 监控进程(如 Java 进程,PID 为 570864)的指定事件 |
常用事件(-e 选项)
cpu-clock:CPU 时钟周期,反映程序的 CPU 耗时。task-clock:任务(进程)占用的 CPU 时间(单位:ms)。cs:上下文切换次数(包括进程间切换和线程间切换),过多会导致性能下降。cache-references:缓存访问次数。cache-misses:缓存未命中次数(cache-misses / cache-references反映缓存效率)。instructions:CPU 执行的指令数(可计算instructions / cycles衡量指令效率)。branches:分支指令数(如if、for跳转)。branch-misses:分支预测失败次数(预测失败会导致流水线停顿)。
示例:监控 Java 进程
1 | 监控进程 570864 的 CPU 时钟、上下文切换、缓存命中情况 |
输出示例:
1 | 性能计数器统计对于进程 ID 570864: |
解读:
- 若
cpu-clock接近time elapsed,说明程序是 CPU 密集型; - 若
cs数值过大(如每秒数万次),可能存在过多线程切换; - 若
cache-misses占比高(如 >20%),可能存在缓存使用效率低的问题(如频繁访问大数组导致缓存失效)。
perf top:实时查看 CPU 热点函数
perf top 实时显示当前系统中消耗 CPU 最多的函数,适合快速定位哪个函数或模块占用资源最多。
基本用法
1 | 实时监控,按 CPU 使用率排序(默认) |
输出解读
1 | Samples: 1K of event 'cpu-clock', Event count (approx.): 123456 |
Overhead:函数占用 CPU 的百分比;Symbol:函数名(C++ 函数可能经过名称修饰,如_ZN13G1CollectedHeap...是 JVM G1 垃圾回收相关函数);- 若 Java 应用的热点函数多为
libjvm.so中的 JVM 内部函数(如 GC 相关),可能说明 GC 频繁是瓶颈;若多为业务类(如com.example.Service),则需优化业务代码。
perf record + perf report:深入分析函数调用开销
perf record 记录程序运行时的详细性能事件,perf report 生成可视化报告,适合深入分析函数级别的耗时分布。
基本流程
记录事件:
1
2记录进程 570864 的性能事件(默认记录 CPU 周期)
perf record -p 570864 -g # -g 记录函数调用栈,便于分析调用关系执行后按
Ctrl+C停止,生成perf.data文件。生成报告:
1
perf report # 解析 perf.data,交互式展示结果
报告解读
报告按函数 CPU 使用率排序,可查看每个函数的调用栈(因 -g 选项),例如:
1 | - 30.0% java libjvm.so |
通过调用栈可追踪性能开销的源头(如上述示例中 GC 线程占用大量 CPU,可能需要优化 JVM 内存配置)。
Java 应用分析注意事项
- 符号解析:
分析 Java 应用时,perf可能无法直接显示 Java 方法名(默认显示 JVM 内部函数)。需通过以下方式让perf识别 Java 方法:- 启动 Java 时添加
-XX:+PreserveFramePointer(保留栈帧指针,便于perf解析调用栈); - 使用
perf report --demangle=java尝试解析 Java 方法名。
- 启动 Java 时添加
- 结合 JVM 工具:
perf侧重底层(CPU、缓存、系统调用),需结合 JVM 工具(如jstack、jstat)定位问题。例如:- 若
perf显示 GC 函数耗时多,用jstat -gc <PID>确认 GC 频率和耗时; - 若
cs(上下文切换)多,用jstack <PID>查看线程状态(是否有大量RUNNABLE线程竞争 CPU)
- 若
v1.3.10