火焰图基本使用指南

适用场景:C++ 服务在生产/测试环境中出现 CPU 占用率异常偏高,需要快速定位热点函数与性能瓶颈。


1. 什么是火焰图

火焰图(Flame Graph)由 Netflix 性能工程师 Brendan Gregg 于 2011 年发明,是一种将大量堆栈采样(stack trace)数据可视化的方法。它将调用栈从底部到顶部排列,宽度代表函数在采样中出现的次数(即 CPU 占用比例),使得最"热"的代码路径一目了然。

火焰图的视觉结构

bash 复制代码
┌─────────────────────────────────────────────────────────┐
│                    hotFunction()                        │  ← 顶层:叶子函数,直接消耗 CPU
├────────────────────────┬────────────────────────────────┤
│    computeHash()       │       processData()            │  ← 中间层:调用者
├────────────────────────┴────────────────────────────────┤
│                      main()                             │  ← 底层:入口函数
└─────────────────────────────────────────────────────────┘

  ◄──────────────── 宽度 = 采样次数(占比) ──────────────►

核心规则

  • Y 轴:调用栈深度(从下往上是调用链)
  • X 轴不代表时间,仅为按字母排序的并列展示
  • 宽度:函数在采样中出现的次数,越宽说明 CPU 占用越高
  • 颜色:默认为随机暖色调,无特殊含义(除非使用差分火焰图)

2. 火焰图的核心原理

2.1 基于采样的性能分析

火焰图依赖采样型 profiler(如 perf),其工作方式是:
⏱ 每隔 ~10ms

(99 Hz)
⚡ 中断 CPU
📋 记录当前线程

完整调用栈
📊 汇总所有样本
🔥 生成火焰图

为什么用 99 Hz 而不是 100 Hz? 避免与系统定时器(通常为 100 Hz)产生共振,导致采样偏差。

2.2 采样 vs 插桩

特性 采样(Sampling) 插桩(Instrumentation)
开销 极低(1-5%) 较高(10-50%+)
精度 统计近似 精确计数
适用场景 生产环境、长时间运行 开发环境、短时间分析
代表工具 perf, DTrace Valgrind, gprof
火焰图常用

3. 工具链总览

Linux 平台(推荐)

工具 用途 安装方式
perf Linux 内核级采样 profiler sudo apt install linux-tools-$(uname -r)
FlameGraph Brendan Gregg 的火焰图生成脚本 git clone https://github.com/brendangregg/FlameGraph
hotspot 图形化 perf 分析工具 sudo apt install hotspot

跨平台替代方案

工具 平台 说明
Instruments macOS Xcode 自带,支持 Time Profiler
VTune Linux/Windows/macOS Intel 出品,专业级
Tracy 跨平台 游戏行业常用,实时帧级分析
Visual Studio Profiler Windows 内置于 Visual Studio
gperftools (pprof) Linux/macOS Google 出品,支持 CPU + 内存

4. 环境准备

4.1 安装 perf

bash 复制代码
# Ubuntu / Debian
sudo apt update
sudo apt install linux-tools-common linux-tools-$(uname -r)

# CentOS / RHEL
sudo yum install perf

# 验证安装
perf --version

4.2 下载 FlameGraph 脚本

bash 复制代码
git clone https://github.com/brendangregg/FlameGraph.git
cd FlameGraph
ls *.pl   # 确认脚本存在
# stackcollapse-perf.pl  flamegraph.pl  difffolded.pl ...

4.3 编译 C++ 程序的关键参数

为了让火焰图显示有意义的函数名(而非一堆地址),编译时必须包含调试信息:

bash 复制代码
# 推荐:保留调试符号 + 开启优化(模拟生产环境行为)
g++ -O2 -g -fno-omit-frame-pointer -o my_program main.cpp

# 各参数说明:
#   -O2                    : 开启优化,保持与生产一致
#   -g                     : 生成调试符号(DWARF),让 perf 能解析函数名
#   -fno-omit-frame-pointer: 保留帧指针,确保 perf 能正确回溯调用栈

!CAUTION

如果不加 -fno-omit-frame-pointer,高优化级别下 GCC/Clang 会省略帧指针寄存器(RBP),

导致 perf 无法正确展开调用栈,火焰图上会出现大量 [unknown] 或断裂的调用链。


5. 实战:用 perf + FlameGraph 排查 CPU 热点

完整流程(5 步)

❶ 采样

perf record

-F 99 -g -p PID
❷ 解析

perf script

→ 文本格式
❸ 折叠栈

stackcollapse-perf.pl

→ 单行格式
❹ 生成SVG

flamegraph.pl

→ 交互式火焰图
❺ 分析

浏览器打开 SVG

搜索 / 缩放 / 悬停

步骤 1:采样

bash 复制代码
# 方式一:启动程序并采样(适合可重复的场景)
sudo perf record -F 99 -g -p $(pgrep my_program) -- sleep 30

# 方式二:直接运行并采样(适合短生命周期程序)
sudo perf record -F 99 -g -- ./my_program

# 参数说明:
#   -F 99   : 采样频率 99 Hz
#   -g      : 记录调用栈(call graph)
#   -p PID  : 附着到已运行的进程
#   sleep 30: 采样持续 30 秒

!TIP

采样时间建议 :对于稳态运行的服务,采样 30-60 秒足够反映典型行为。

对于间歇性 CPU 飙高的场景,可以结合监控在 CPU 飙高时触发采样。

步骤 2:解析 perf 数据

bash 复制代码
# 将二进制 perf.data 转为可读文本
sudo perf script > perf_output.txt

# 查看前几行,确认数据正常
head -20 perf_output.txt

输出示例:

复制代码
my_program  3892 [001] 94564.456783: cpu-clock:
        7f2d1a hotFunction+0x14 (/home/user/my_program)
        7f2d3b computeHash+0x2b (/home/user/my_program)
        7f2d5c processData+0x1c (/home/user/my_program)
        7f2d8e main+0x4e (/home/user/my_program)
        7f0821 __libc_start_main+0xf1 (/lib/x86_64-linux-gnu/libc.so.6)

步骤 3:折叠调用栈

bash 复制代码
# 使用 FlameGraph 脚本将 perf 输出折叠为单行格式
./FlameGraph/stackcollapse-perf.pl perf_output.txt > folded_stacks.txt

# 查看折叠后的格式
head -5 folded_stacks.txt

折叠后格式(每行一个调用栈 + 出现次数):

复制代码
my_program;__libc_start_main;main;processData;computeHash;hotFunction 3542
my_program;__libc_start_main;main;processData;sortResults 892
my_program;__libc_start_main;main;handleRequest;parseJSON 234

步骤 4:生成火焰图 SVG

bash 复制代码
# 基础生成
./FlameGraph/flamegraph.pl folded_stacks.txt > flamegraph.svg

# 带定制参数的生成
./FlameGraph/flamegraph.pl \
    --title "My C++ Service CPU Flame Graph" \
    --subtitle "Sampled at 99 Hz for 30s, 2026-03-04" \
    --width 1200 \
    --colors hot \
    --countname samples \
    folded_stacks.txt > flamegraph.svg

步骤 5:在浏览器中分析

bash 复制代码
# 用浏览器打开 SVG(火焰图是交互式的!)
firefox flamegraph.svg
# 或
google-chrome flamegraph.svg

交互功能

  • 🖱️ 悬停:显示函数名、采样次数和占比
  • 🔍 点击:放大某个调用栈分支
  • 🔎 Ctrl+F:搜索函数名(匹配项高亮为紫色)
  • ↩️ Reset Zoom:点击左上角重置缩放

一键脚本

将上述步骤整合为一个脚本,方便日常使用:

bash 复制代码
#!/bin/bash
# flamegraph.sh - 一键生成 C++ 程序的火焰图
# 用法: ./flamegraph.sh <PID> <采样秒数> <输出文件名>

set -euo pipefail

PID=${1:?"Usage: $0 <PID> <DURATION_SEC> <OUTPUT_NAME>"}
DURATION=${2:-30}
OUTPUT=${3:-"flamegraph"}
FLAMEGRAPH_DIR=${FLAMEGRAPH_DIR:-"./FlameGraph"}

echo "🔥 [1/4] 采样进程 PID=$PID,持续 ${DURATION}s ..."
sudo perf record -F 99 -g -p "$PID" -- sleep "$DURATION"

echo "📝 [2/4] 解析 perf 数据 ..."
sudo perf script > /tmp/perf_output.txt

echo "📦 [3/4] 折叠调用栈 ..."
"$FLAMEGRAPH_DIR/stackcollapse-perf.pl" /tmp/perf_output.txt > /tmp/folded.txt

echo "🎨 [4/4] 生成火焰图 ..."
"$FLAMEGRAPH_DIR/flamegraph.pl" \
    --title "CPU Flame Graph - PID $PID" \
    --subtitle "$(date '+%Y-%m-%d %H:%M:%S') | ${DURATION}s @ 99Hz" \
    /tmp/folded.txt > "${OUTPUT}.svg"

echo "✅ 火焰图已生成: ${OUTPUT}.svg"
echo "💡 请在浏览器中打开查看: firefox ${OUTPUT}.svg"

6. 完整示例:一个有性能问题的 C++ 程序

6.1 问题代码

以下是一个故意包含性能问题的 C++ 服务模拟代码:

cpp 复制代码
// file: cpu_hog_demo.cpp
// 编译: g++ -O2 -g -fno-omit-frame-pointer -o cpu_hog_demo cpu_hog_demo.cpp -lpthread
// 运行: ./cpu_hog_demo

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#include <thread>
#include <chrono>
#include <numeric>
#include <random>
#include <unordered_map>
#include <sstream>
#include <mutex>

// ============================================================
// 问题 1:低效的字符串拼接(Schlemiel the Painter's algorithm)
// ============================================================
std::string buildReport_Bad(const std::vector<int>& data) {
    std::string result;
    for (size_t i = 0; i < data.size(); ++i) {
        // 🐛 每次 += 都可能触发内存重分配和拷贝
        result += "Item #" + std::to_string(i) + ": value=" 
                + std::to_string(data[i]) + "\n";
    }
    return result;
}

// ✅ 修复版本:使用 ostringstream 或 reserve
std::string buildReport_Good(const std::vector<int>& data) {
    std::ostringstream oss;
    for (size_t i = 0; i < data.size(); ++i) {
        oss << "Item #" << i << ": value=" << data[i] << "\n";
    }
    return oss.str();
}


// ============================================================
// 问题 2:不必要的深拷贝
// ============================================================
struct LargeObject {
    std::vector<double> matrix;
    std::string name;
    
    LargeObject() : matrix(10000, 3.14), name("default") {}
};

// 🐛 按值传递,每次调用都会深拷贝一个 80KB 的对象
double processObject_Bad(LargeObject obj) {
    double sum = 0;
    for (auto& val : obj.matrix) {
        sum += std::sin(val) * std::cos(val);
    }
    return sum;
}

// ✅ 修复版本:使用 const 引用
double processObject_Good(const LargeObject& obj) {
    double sum = 0;
    for (auto& val : obj.matrix) {
        sum += std::sin(val) * std::cos(val);
    }
    return sum;
}


// ============================================================
// 问题 3:O(n²) 算法------线性查找代替哈希查找
// ============================================================
struct Record {
    int id;
    std::string payload;
};

// 🐛 在 vector 中线性查找,O(n) 每次查找 × n 次 = O(n²)
std::string findRecord_Bad(const std::vector<Record>& records, int targetId) {
    for (const auto& rec : records) {
        if (rec.id == targetId) {
            return rec.payload;
        }
    }
    return "";
}

// ✅ 修复版本:使用 unordered_map,O(1) 查找
std::string findRecord_Good(const std::unordered_map<int, std::string>& recordMap, 
                            int targetId) {
    auto it = recordMap.find(targetId);
    return (it != recordMap.end()) ? it->second : "";
}


// ============================================================
// 问题 4:锁争用(Lock Contention)
// ============================================================
std::mutex globalMutex;
int sharedCounter = 0;

// 🐛 持锁范围过大,包含了不需要同步的计算
void incrementCounter_Bad(int iterations) {
    for (int i = 0; i < iterations; ++i) {
        std::lock_guard<std::mutex> lock(globalMutex);
        // 下面的计算不需要持锁
        double dummy = std::sin(i) * std::cos(i) * std::tan(i + 1);
        sharedCounter += static_cast<int>(dummy);
    }
}

// ✅ 修复版本:缩小临界区
void incrementCounter_Good(int iterations) {
    int localSum = 0;
    for (int i = 0; i < iterations; ++i) {
        double dummy = std::sin(i) * std::cos(i) * std::tan(i + 1);
        localSum += static_cast<int>(dummy);
    }
    std::lock_guard<std::mutex> lock(globalMutex);
    sharedCounter += localSum;
}


// ============================================================
// 模拟工作负载
// ============================================================
void simulateWorkload() {
    // 生成测试数据
    std::mt19937 rng(42);
    std::uniform_int_distribution<int> dist(1, 1000000);
    
    // 准备大数据集
    std::vector<int> reportData(50000);
    std::generate(reportData.begin(), reportData.end(), [&]{ return dist(rng); });
    
    LargeObject largeObj;
    
    std::vector<Record> records(100000);
    for (int i = 0; i < 100000; ++i) {
        records[i] = {i, "payload_" + std::to_string(i)};
    }
    
    std::cout << "=== 开始模拟工作负载 ===" << std::endl;
    
    while (true) {
        // 问题 1:低效字符串拼接
        auto report = buildReport_Bad(reportData);
        
        // 问题 2:不必要的深拷贝(循环 100 次放大问题)
        double total = 0;
        for (int i = 0; i < 100; ++i) {
            total += processObject_Bad(largeObj);
        }
        
        // 问题 3:O(n²) 查找
        for (int i = 0; i < 1000; ++i) {
            int target = dist(rng) % 100000;
            findRecord_Bad(records, target);
        }
        
        // 问题 4:锁争用(多线程)
        std::vector<std::thread> threads;
        for (int t = 0; t < 4; ++t) {
            threads.emplace_back(incrementCounter_Bad, 100000);
        }
        for (auto& t : threads) {
            t.join();
        }
        
        std::cout << "." << std::flush;  // 心跳输出
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

int main() {
    std::cout << "CPU Hog Demo - PID: " << getpid() << std::endl;
    std::cout << "Use: sudo perf record -F 99 -g -p " << getpid() 
              << " -- sleep 30" << std::endl;
    
    simulateWorkload();
    return 0;
}

6.2 编译与运行

bash 复制代码
# 编译(注意关键参数)
g++ -O2 -g -fno-omit-frame-pointer -o cpu_hog_demo cpu_hog_demo.cpp -lpthread

# 运行(会打印自己的 PID)
./cpu_hog_demo &
# 输出: CPU Hog Demo - PID: 12345

6.3 采样与生成火焰图

bash 复制代码
# 采样 30 秒
sudo perf record -F 99 -g -p 12345 -- sleep 30

# 生成火焰图
sudo perf script | ./FlameGraph/stackcollapse-perf.pl | \
    ./FlameGraph/flamegraph.pl --title "cpu_hog_demo Flame Graph" > cpu_hog.svg

# 打开查看
firefox cpu_hog.svg

6.4 火焰图分析结果

在火焰图中你会看到类似如下的热点分布:

复制代码
预期火焰图结构(宽度表示 CPU 占比):

main
└── simulateWorkload
    ├── buildReport_Bad ██████████████████ (~35%)
    │   ├── std::string::operator+=
    │   ├── std::to_string
    │   └── malloc / free            ← 频繁内存分配
    │
    ├── processObject_Bad █████████████ (~25%)
    │   ├── LargeObject::LargeObject  ← 拷贝构造
    │   │   └── std::vector::vector   ← 深拷贝 10000 个 double
    │   ├── std::sin / std::cos
    │   └── ~LargeObject              ← 析构(释放拷贝的内存)
    │
    ├── findRecord_Bad ████████████ (~22%)
    │   └── std::string::compare      ← 线性遍历比较
    │
    └── incrementCounter_Bad ████████ (~18%)
        ├── pthread_mutex_lock        ← 锁等待
        ├── std::sin / cos / tan
        └── pthread_mutex_unlock

6.5 根据火焰图定位问题并修复

排名 热点函数 占比 根因 修复方案
1 buildReport_Bad ~35% std::string 反复重分配 改用 ostringstream 或预分配 reserve()
2 processObject_Bad ~25% 按值传参导致深拷贝 改为 const LargeObject&
3 findRecord_Bad ~22% O(n) 线性查找 改用 unordered_map
4 incrementCounter_Bad ~18% 临界区过大 缩小锁的范围,先本地累加再加锁写入

7. 火焰图解读技巧

7.1 快速定位问题的三步法

🔍 打开火焰图
第一步: 看'平顶' (Plateau)
⚠️ 函数顶部很宽 = 自身消耗大量 CPU

例: hotFunction() 占 40%

→ 直接优化该函数
第二步: 看'宽塔' (Wide Tower)
⚠️ 调用链很深且整体宽 = 路径频繁调用

例: main→parse→validate→...→tinyFunc

→ 减少调用频率或缓存中间结果
第三步: Ctrl+F 搜索关键词
malloc / free → 内存分配热点
mutex / lock → 锁争用
memcpy / memmove → 数据拷贝
__GI___clone → 线程创建开销

7.2 常见 CPU 热点模式

火焰图特征 可能的问题 排查方向
malloc/free 占比高 频繁堆内存分配 对象池、预分配、栈上分配
std::string 相关函数宽 字符串操作低效 string_viewreserveostringstream
pthread_mutex_lock 锁争用严重 缩小临界区、无锁数据结构、读写锁
拷贝构造/析构函数宽 不必要的深拷贝 const&std::move、传指针
std::sort 或比较函数宽 排序算法热点 检查比较函数复杂度、部分排序
std::unordered_map::find 哈希冲突多 自定义哈希函数、检查负载因子
非常深的递归塔 递归层数过深 改为迭代、尾递归优化

7.3 使用 Ctrl+F 搜索

火焰图 SVG 内置搜索功能:

复制代码
搜索 "std::vector"  → 高亮所有涉及 vector 操作的帧
搜索 "MyNamespace"  → 高亮所有自己项目的代码(排除标准库)
搜索 "lock"         → 快速定位锁相关的热点

搜索结果会以紫色高亮显示,并在右下角显示匹配帧的总占比。


8. 进阶:差分火焰图

差分火焰图(Differential Flame Graph)用于比较优化前后的 CPU 使用变化,是验证优化效果的利器。

8.1 工作流程

bash 复制代码
# 1. 优化前:采样并生成折叠栈
sudo perf record -F 99 -g -p $PID_BEFORE -- sleep 30
sudo perf script > before.txt
./FlameGraph/stackcollapse-perf.pl before.txt > before_folded.txt

# 2. 优化后:采样并生成折叠栈(部署修复后的代码)
sudo perf record -F 99 -g -p $PID_AFTER -- sleep 30
sudo perf script > after.txt
./FlameGraph/stackcollapse-perf.pl after.txt > after_folded.txt

# 3. 生成差分火焰图
./FlameGraph/difffolded.pl before_folded.txt after_folded.txt \
    | ./FlameGraph/flamegraph.pl \
        --title "Differential Flame Graph (Before → After)" \
        --negate \
    > diff_flamegraph.svg

8.2 颜色含义

颜色 含义
🔴 红色 优化后 CPU 占用增加(性能退化)
🔵 蓝色 优化后 CPU 占用减少(性能改善 ✅)
白色 无明显变化

8.3 实际案例

bash 复制代码
# 对示例程序,修复 buildReport_Bad → buildReport_Good 后:
# 差分火焰图中,buildReport 栈会显示为亮蓝色,
# 表示 CPU 占用显著降低

# 搜索 "buildReport" 可快速确认效果

9. 进阶:Off-CPU 火焰图

有时程序的问题不是 CPU 占用高,而是等待时间过长(I/O、锁、sleep)。Off-CPU 火焰图可以帮助排查这类问题。

9.1 On-CPU vs Off-CPU

程序运行时间线
On-CPU

🔥 CPU 上执行代码

─────────────────

分析工具: CPU Flame Graph

perf record -F 99 -g
Off-CPU

⏳ 等待中 (I/O / 锁 / sleep)

─────────────────

分析工具: Off-CPU Flame Graph

perf record -e sched:sched_switch

或 bpftrace / BCC tools

9.2 使用 bpftrace 生成 Off-CPU 火焰图

bash 复制代码
# 安装 bpftrace
sudo apt install bpftrace

# 采集 Off-CPU 数据(需要 Linux 4.8+ 内核)
sudo bpftrace -e '
    kprobe:finish_task_switch {
        @[kstack, ustack, comm] = count();
    }
' -p $PID > offcpu_stacks.txt

# 或使用 BCC 工具
sudo /usr/share/bcc/tools/offcputime -df -p $PID 30 > offcpu_folded.txt

# 生成 Off-CPU 火焰图(推荐使用蓝色色调区分)
./FlameGraph/flamegraph.pl \
    --title "Off-CPU Flame Graph" \
    --colors io \
    --countname "microseconds" \
    offcpu_folded.txt > offcpu_flamegraph.svg

10. 常见问题与排查

Q1: 火焰图中全是 [unknown]

原因:缺少调试符号或帧指针未保留。

bash 复制代码
# 检查二进制是否包含调试符号
file my_program
# 应该包含 "not stripped" 或 "with debug_info"

readelf -S my_program | grep debug
# 应该能看到 .debug_info 等段

# 解决方案:重新编译
g++ -O2 -g -fno-omit-frame-pointer -o my_program main.cpp

Q2: 火焰图中调用栈不完整 / 只有一两层

原因 :帧指针被优化掉了(GCC -O2 默认行为)。

bash 复制代码
# 方案 1(推荐):加 -fno-omit-frame-pointer 重新编译
g++ -O2 -g -fno-omit-frame-pointer ...

# 方案 2:使用 DWARF 展开(不需要帧指针,但开销稍大)
sudo perf record -F 99 --call-graph dwarf -p $PID -- sleep 30

# 方案 3:使用 LBR(Last Branch Record,Intel CPU 专属,零开销)
sudo perf record -F 99 --call-graph lbr -p $PID -- sleep 30

Q3: perf record 报 "Permission denied"

bash 复制代码
# 临时修改(重启失效)
echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid

# 或以 root 运行
sudo perf record ...

# 永久修改(添加到 sysctl)
echo "kernel.perf_event_paranoid = -1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Q4: 我的程序是多线程的,如何分析特定线程?

bash 复制代码
# 方法 1:在火焰图中搜索线程名(如果程序设置了线程名)
# Ctrl+F 搜索线程名

# 方法 2:采样时指定线程 TID
sudo perf record -F 99 -g -t $TID -- sleep 30

# 方法 3:使用 --per-thread 模式,为每个线程单独生成
sudo perf record -F 99 -g -p $PID --per-thread -- sleep 30

Q5: 如何分析动态链接库中的热点?

bash 复制代码
# 确保 .so 文件也带调试符号
g++ -O2 -g -fno-omit-frame-pointer -shared -fPIC -o libfoo.so foo.cpp

# 如果是第三方库,安装 debuginfo 包
sudo apt install libc6-dbg          # glibc 调试符号
sudo apt install libstdc++6-dbg     # libstdc++ 调试符号

11. 最佳实践清单

编译阶段

  • 始终使用 -g 保留调试符号
  • 始终使用 -fno-omit-frame-pointer
  • 使用与生产一致的优化级别(-O2
  • .so 文件也保留调试符号

采样阶段

  • 使用 -F 99(避免共振采样偏差)
  • 采样时长覆盖程序的典型工作周期
  • 在 CPU 实际飙高时采样(而非空闲期)
  • 确认 perf script 输出包含函数名

分析阶段

  • 先看最宽的"平顶"函数
  • Ctrl+F 搜索项目自己的命名空间
  • 关注 malloclock、拷贝构造等系统级热点
  • 对比优化前后使用差分火焰图

团队协作

  • 将火焰图 SVG 保存到版本控制或 Wiki
  • 性能基准测试中自动生成火焰图(CI/CD 集成)
  • 建立性能回归检测流程

12. 参考资料

资源 链接
Brendan Gregg 火焰图官方网站 https://www.brendangregg.com/flamegraphs.html
FlameGraph GitHub 仓库 https://github.com/brendangregg/FlameGraph
perf 官方文档 https://perf.wiki.kernel.org/index.php/Main_Page
Brendan Gregg《Systems Performance》 ISBN: 978-0136820154
perf Examples https://www.brendangregg.com/perf.html
Intel VTune Profiler https://www.intel.com/content/www/us/en/developer/tools/oneapi/vtune-profiler.html
hotspot GUI 工具 https://github.com/KDAB/hotspot
gperftools (pprof) https://github.com/gperftools/gperftools

作者提示 :性能优化是一个迭代过程。火焰图帮助你找到问题 ,但修复后一定要再次采样验证

使用差分火焰图可以直观地确认优化效果,避免"优化了寂寞"的尴尬情况。

是 ✓
🔬 采样

perf record
🔥 生成火焰图

定位热点
🔧 修复代码

针对性优化
🔬 再次采样

perf record
📊 差分对比

difffolded.pl
效果满意?
✅ 优化完成

相关推荐
MC皮蛋侠客4 小时前
Perf 火焰图深度实战:CPU 性能分析与异常排查完全指南
linux·c++·性能分析·perf·火焰图
拉不拉斯5 天前
Linux 性能调优实战指南:从 perf 实时监控到火焰图生成
linux·运维·服务器·perf
H Journey1 个月前
C++ 性能瓶颈分析与优化
c++·性能优化·gprof·perf·valgrind·瓶颈分析
罗小爬EX2 个月前
Arthas 实战指南(二):profiler生成火焰图实战
java·arthas·火焰图
weisian1512 个月前
Java并发编程--24-死锁排查与性能调优:线上并发问题诊断指南(死锁,CPU飙升,内存溢出)
java·开发语言·arthas·死锁·火焰图·cpu飙升
liulilittle2 个月前
eBPF tc prog
服务器·网络·c++·网络协议·tcp/ip·性能·perf
Jia ming3 个月前
Linux性能分析工具perf全面解析
linux·性能优化·perf
JiMoKuangXiangQu4 个月前
Linux perf 子系统一览
linux·perf
九皇叔叔4 个月前
使用 perf + FlameGraph 生成火焰图(Flame Graph)笔记
笔记·性能分析·火焰图