news 2026/4/15 18:21:49

[fastgrind] 一个轻量级C++内存监控及可视化开源库

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[fastgrind] 一个轻量级C++内存监控及可视化开源库

引言

在高性能计算场景下,常使用perf工具进行函数级别的时间分析、使用valgrind工具进行内存泄漏和内存分配异常检测。

valgrind功能非常强大,能追踪每一段内存申请和释放的栈帧。但是valgrind使用相对复杂,最重要的是valgrind效率极其低下,通常为原始程序运行时间长的10倍以上。对于多线程程序,valgrind无法跑满线程,性能退化能到几十甚至上百倍。

大部分场景下,即使精简case后,valgrind依然难以快速定位内存异常问题。

对于上述问题,fastgrind开源库提供一个轻量级的、函数级别监控、可视化的、高效C++内存监控方案。在64核服务器上测试,64个线程能完全跑满。简单case (调用栈深度10以内),性能几乎无退化;复杂case (调用栈深度30+),性能退化4倍以内。

box grouping

fastgrind仓库的testcase中,提供了一个包含bin query、分组算法的box grouping测例,调整线程数量,测试得到的benchmark如上图所示。

简介

fastgrind 是一个仅单一头文件、轻量级、快速、线程安全、类似 Valgrind 的内存分析器,旨在跟踪 C++ 应用程序中的运行时内存分配并分析调用堆栈。Fastgrind 通过自动和手动插桩两种检测方法提供全面的内存使用情况分析。

fastgrind 兼容C++11以上版本,集成到工程中不影响原始仓库中其它第三方内存管理库或glibc内存管理的正常运行。

仓库结构

fastgrind/

├── include/fastgrind.h # 核心代码 (head only)

|

├── demo/

│ ├── manual_instrument/ # 手动插桩 demos

│ ├── auto_instrument/ # 自动插桩 demos

| └── build_all_demo.sh # 编译所有demo的脚本

|

├── testcase/

│ ├── benchmark_box_grouping/ # 性能测试

│ ├── cpp_feature_test/ # 现代C++特性测试

│ ├── glibc_je_tc_availabe/ # 分配器兼容性测试

│ ├── multi_pkg_compile/ # 多lib编译测试

| ├── thirdparty_leveldb_test/ # 第三方开源库测试 (https://github.com/google/leveldb)

| └── thirdparty_zlib_test # 第三方开源库测试 (https://zlib.net)

|

├── doc/

| ├── compile.md # 集成和编译选项说明

| ├── demo.md # demo说明

| ├── feature_list.md # fastgrind特性说明

| ├── querstion_list.md # fastgrind使用过​​程中出现的问题及解决方案说明

| └── testcase.md # testcase说明

|

├── tools/fastgrind.py # 可视化工具 (使用方法:python fastgrind.py fastgrind.json)

|

├── CMakeList.txt # testcase的顶层Cmake

├── Doxyfile # Doxyfile生成手册

└── README.md # 存库描述

快速开始

编译 testcase

mkdir build && cd build

cmake ..

make -j$(nproc)

运行 testcase

cd build/testcase/benchmark_box_grouping

./benchmark_raw

./benchmark_fastgrind

./run_valgrind.sh

cd build/testcase/cpp_feature_test

./cpp_feature_test

...

cd build/testcase/multi_pkg_compile

./multi_pkg_main

调用堆栈 Report

程序退出时会生成两个报告文件

[FASTGRIND] Start summary memory info

[FASTGRIND] saved: fastgrind.text (size=2335 bytes)

[FASTGRIND] saved: fastgrind.json (size=65952 bytes)

更多细节请看本文段落: fastgrind 输出与分析

如何在你的项目中使用

手动和自动插桩都需要额外的编译标志

有关详细编译和链接选项,请看本文段落: fastgrind 编译选项

手动插桩的使用方法

通过显示的插入__FASTGRIND__::FAST_GRIND宏,选择要监控的函数。

#include "fastgrind.h"

using namespace __FASTGRIND__;

void processData() {

FAST_GRIND; // 启用此函数的调用堆栈跟踪

int* data = new int[1000];

// ... process data ...

delete[] data;

}

int main() {

FAST_GRIND; // 启用此函数的调用堆栈跟踪

processData();

return 0;

}

自动插桩的使用方法

在任何一个.cpp中包含 fastgrind.h,并通过编译选项,使得目标外的所有函数都会自动监控。

fastgrind 输出与分析

当集成 fastgrind 的应用程序退出时,会自动生成两个文件:fastgrind.text和fastgrind.json

fastgrind.text

​fastgrind.text 是类似于 Linux 下 perf report 格式的输出。有函数级别的调用栈内存申请/释放统计,在vscode等editor下可以进行子调用栈折叠。

zlib-ouput示意图

fastgrind.json

fastgrind.json 文件中包含:

时间片内存使用统计

每线程内存分配详细信息

完整的调用堆栈信息

函数级分配明细

每时间片、每线程、每函数记录器:

单线程记录如下

单线程

多线程记录如下

多线程

可视化

使用tools/fastgrind.py生成交互式可视化折线图

它将调用 matplotlib 绘制折线图,​​并生成 fastgrind.html以防用户环境中没有 matplotlib,使用浏览器打开fastgrind.html可以得到与matplotlib相同的折线图

用法

python fastgrind.py fastgrind.json

or

python fastgrind.py # 自动搜索当前文件夹中的 fastgrind.json

以第三方开源库 leveldb 为例,监控其内存分配:

matplot结果

leveldb_plot

html结果

leveldb_html

fastgrind 编译选项

手动插桩的编译选项

描述: 手动检测要求开发人员在源代码中显式添加__FASTGRIND__::FAST_GRIND到需要监控的函数,但只需要更简单的编译配置

编译选项:

g++ -O3 -Wall -Wextra -std=c++11 \

-I/path/to/fastgrind/include \

source_files...

# -DFASTGRIND_JE_MALLOC (如果原工程中使用jemalloc的话需要定义该选项)

# -DFASTGRIND_TC_MALLOC (如果原工程中使用tcmalloc的话需要定义该选项)

链接选项:

Wrap flags: 内存分配器的符号包装(下面列出了所有支持的)

WRAP_FLAGS=(

# C standard library memory allocation functions

-Wl,--wrap=malloc # Standard memory allocation

-Wl,--wrap=calloc # Zero-initialized memory allocation

-Wl,--wrap=realloc # Memory reallocation

-Wl,--wrap=free # Memory deallocation

# C++ standard operator new/delete (basic versions)

-Wl,--wrap=_Znwm # operator new(size_t)

-Wl,--wrap=_Znam # operator new[](size_t)

-Wl,--wrap=_ZdlPv # operator delete(void*)

-Wl,--wrap=_ZdaPv # operator delete[](void*)

# C++ nothrow operator new/delete

-Wl,--wrap=_ZnwmRKSt9nothrow_t # operator new(size_t, nothrow)

-Wl,--wrap=_ZnamRKSt9nothrow_t # operator new[](size_t, nothrow)

-Wl,--wrap=_ZdlPvRKSt9nothrow_t # operator delete(void*, nothrow)

-Wl,--wrap=_ZdaPvRKSt9nothrow_t # operator delete[](void*, nothrow)

# POSIX and Linux-specific memory allocation functions

-Wl,--wrap=valloc # Page-aligned memory allocation

-Wl,--wrap=pvalloc # Page-aligned allocation (multiple of page size)

-Wl,--wrap=memalign # Aligned memory allocation

-Wl,--wrap=posix_memalign # POSIX aligned memory allocation

-Wl,--wrap=reallocarray # Array reallocation with overflow check

-Wl,--wrap=aligned_alloc # C11 aligned allocation

# C++ sized delete operators (C++14)

-Wl,--wrap=_ZdaPvm # operator delete[](void*, size_t)

-Wl,--wrap=_ZdlPvm # operator delete(void*, size_t)

# C++ aligned allocation operators (C++17)

-Wl,--wrap=_ZnwmSt11align_val_t # operator new(size_t, align_val_t)

-Wl,--wrap=_ZnamSt11align_val_t # operator new[](size_t, align_val_t)

-Wl,--wrap=_ZdlPvSt11align_val_t # operator delete(void*, align_val_t)

-Wl,--wrap=_ZdaPvSt11align_val_t # operator delete[](void*, align_val_t)

# C++ sized aligned delete operators (C++17)

-Wl,--wrap=_ZdlPvmSt11align_val_t # operator delete(void*, size_t, align_val_t)

-Wl,--wrap=_ZdaPvmSt11align_val_t # operator delete[](void*, size_t, align_val_t)

# C++ nothrow sized delete operators

-Wl,--wrap=_ZdlPvmRKSt9nothrow_t # operator delete(void*, size_t, nothrow)

-Wl,--wrap=_ZdaPvmRKSt9nothrow_t # operator delete[](void*, size_t, nothrow)

# C++ nothrow aligned allocation operators (C++17)

-Wl,--wrap=_ZnwmSt11align_val_tRKSt9nothrow_t # operator new(size_t, align_val_t, nothrow)

-Wl,--wrap=_ZnamSt11align_val_tRKSt9nothrow_t # operator new[](size_t, align_val_t, nothrow)

-Wl,--wrap=_ZdlPvSt11align_val_tRKSt9nothrow_t # operator delete(void*, align_val_t, nothrow)

-Wl,--wrap=_ZdaPvSt11align_val_tRKSt9nothrow_t # operator delete[](void*, align_val_t, nothrow)

# C++ nothrow sized aligned delete operators

-Wl,--wrap=_ZdlPvmSt11align_val_tRKSt9nothrow_t # operator delete(void*, size_t, align_val_t, nothrow)

-Wl,--wrap=_ZdaPvmSt11align_val_tRKSt9nothrow_t # operator delete[](void*, size_t, align_val_t, nothrow)

)

具体示例可看原仓库中demo/manual_instrument

自动插桩的编译选项

描述: 自动插桩能监控所有非排除函数,但需要更复杂的编译配置

编译选项:

# 不需要监控的库或pkg

EXCLUDE_FILE_LISTS=(

/usr/include/

/usr/lib/

/usr/local/

fastgrind.h

)

EXCLUDE_FILE_LISTS=$(IFS=,; echo "${EXCLUDE_FILE_LISTS[*]}")

# 函数插桩的编译选项

INSTRUMENT_FLAGS=(

-finstrument-functions

-finstrument-functions-exclude-file-list=${EXCLUDE_FILE_LISTS}

)

# "${INSTRUMENT_FLAGS[@]}": 不要监控的库或pkg

# -DFASTGRIND_INSTRUMENT: 定义 FASTGRIND_INSTRUMENT 以启动自动插桩

# -Wl,--export-dynamic: 导出符号表,便于fastgrind抓取函数名

g++ -O3 -Wall -Wextra -std=c++11 \

"${INSTRUMENT_FLAGS[@]}" \

-DFASTGRIND_INSTRUMENT \

-Wl,--export-dynamic \

-I/path/to/fastgrind/include \

source_files...

# -DFASTGRIND_JE_MALLOC (如果原工程中使用jemalloc的话需要定义该选项)

# -DFASTGRIND_TC_MALLOC (如果原工程中使用tcmalloc的话需要定义该选项)

链接选项:

同 手动插桩 一致

具体示例可看原仓库中demo/auto_instrument

限制和注意事项

跨函数栈帧分配: 在一个函数中分配并在另一个函数中释放的内存将被如实记录,导致这些函数堆栈帧记录释放的数量少于或超过分配的数量,在另一些则相反.

模板复杂性支持: 复杂的模板元编程可能会在报告中显示通用名称

文件覆盖: 每次运行时输出文件都会覆盖以前的内容

GUN依赖: 需要 GNU ld 来实现 --wrap 功能

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 14:17:10

Linux日志查询全攻略:常用命令与实战技巧

Linux日志查询全攻略:常用命令与实战技巧 在Linux系统运维、应用问题排查过程中,日志是最核心的“诊断依据”——它记录了系统启动、进程运行、用户操作、应用报错等所有关键信息。掌握Linux日志查询命令,能帮我们快速定位问题根源&#xff0…

作者头像 李华
网站建设 2026/4/16 14:20:45

4步掌握Element Plus多文件上传:快速解决文件数量控制难题

4步掌握Element Plus多文件上传:快速解决文件数量控制难题 【免费下载链接】element-plus element-plus/element-plus: Element Plus 是一个基于 Vue 3 的组件库,提供了丰富且易于使用的 UI 组件,用于快速搭建企业级桌面和移动端的前端应用。…

作者头像 李华
网站建设 2026/4/16 14:19:28

其鼎新推出的BM-S4光时域反射仪就以其远距离的光纤检测、卓越的性能、操作的便捷等多方面的优点深受广大用户的青睐

作为光纤的“心脏外科医生”,BM-S4的OTDR光时域反射仪就如同对光纤的精准的“手术”,能够快速准确的对光纤的各个参数进行检测,对于光纤的故障和隐患的早期发现具有十分重要的意义对光纤通信的精准的故障定位和性能的科学的评估都成为了这一领…

作者头像 李华
网站建设 2026/4/15 14:46:38

MAC用户必备:终极中文排版字体解决方案

在当今数字化时代,MAC用户在日常工作和学习中经常需要处理中文文档的排版问题。无论是撰写工作报告、学术论文,还是设计宣传材料,字体的选择都直接影响到最终呈现的专业度和美观性。今天,我们将为您介绍一款专为MAC系统优化的中文…

作者头像 李华
网站建设 2026/4/16 11:05:47

快速掌握mcp-agent:构建智能AI代理系统的终极指南

快速掌握mcp-agent:构建智能AI代理系统的终极指南 【免费下载链接】mcp-agent Build effective agents using Model Context Protocol and simple workflow patterns 项目地址: https://gitcode.com/GitHub_Trending/mc/mcp-agent 还在为AI代理开发的复杂性而…

作者头像 李华
网站建设 2026/4/16 10:42:01

Beyond Compare 文件对比神器,提高工作效率

作为程序员,日常开发中总离不开各种比较操作。还记得那些令人头疼的场景吗? 代码对比场景:昨天改了三四个文件,今天测试说有个功能不对劲了。是哪个文件改出问题了?🤔 直接把当前版本和Git上昨天的版本拖进…

作者头像 李华