一、安装

使用以下命令编译安装。

1
2
3
4
5
6
7
8
9
wget https://github.com/jemalloc/jemalloc/archive/refs/tags/5.3.0.tar.gz
tar zxvf 5.3.0.tar.gz
cd jemalloc-5.3.0/
./autogen.sh 

# 这里启动堆剖析功能
./configure --enable-prof 
make -j 
make install

二、使用

2.1 堆分析

一般来说有两种使用方法,一种是直接编译到程序中,我没有使用这种方法,原因是在我的使用场景中,程序需要加载一些别人的代码,而别人的代码也可能有内存上的问题,而我无法控制让别人也编译 jemalloc,因此还是使用第二种方法,即通过注入的方式使用。

设置 LD_PRELOAD 环境变量,进行注入。

1
2
# 这里要设置成自己安装的路径
export LD_PRELOAD=/usr/local/lib/libjemalloc.so

注入完毕后,进行采样配置。

1
export MALLOC_CONF="prof:true,lg_prof_interval:26,lg_prof_sample:20,prof_prefix:jeprof.out"

这里对采样配置进行说明。

  • prof:true, 打开堆剖析的功能。
  • lg_prof_interval:26,生成内存转储的平均间隔(以 2 为底的对数),以分配活动字节数为单位。这里设置为 26,即每申请 2^26 字节的内存就生成一份到本地的内存转储配置。
  • lg_prof_sample:20,采样内存的平均间隔(以 2 为底的对数),以分配活动字节数为单位。这里设置为 20,即每申请 2^20 字节的内存就会采样一次。默认情况下是 2^19(512KB)。
  • prof_prefix: jeprof.out,设置生成的采样结果的文件名前缀。

配置完毕后,执行自己的程序,便会生成 jeprof.out 开头的内存转储文件了。接下来需要对这些内存转储文件进行分析。

可以使用以下命令对比每两次分配活动中,哪里占用的内存最多。

1
2
# 安装jemalloc后,默认会安装jeprof工具
jeprof --lines --svg <exec_name>  --base jeprof.out.0.heap jeprof.out.3.heap > <exec_name>.svg

上述命令的参数说明如下,执行完毕后,将会生成 svg 图,分析 svg 图即可了解当前程序中哪里占用的内存较多。

  • –lines 参数要求输出行号。
  • –svg 参数指定生成 svg 格式的结果。
  • –base 参数指定要比对的第一个 heap 文件(转储文件)。
  • <exec_name> 用来指定刚刚运行的程序,用来获取符号等信息(程序编译时需要加 -g 参数)。

注意, 在使用 jeprof 命令生成 svg 图时,可能报错 dot not found,这是因为系统上缺少生成 svg 图的工具,使用命令 sudo apt install graphviz gv 安装即可。

在通过环境变量配置 LD_PRELOADMALLOC_CONF 参数时,会有一个问题,即之后执行的所有命令都会被注入 jemalloc.so,同时生成相应的转储文件,而这并不在我们预期中。

可以通过以下形式执行命令,仅在执行我们的程序时才生成转储文件。

1
2
3
4
5
# 使用环境变量设置参数
export MALLOC_CONF="prof:true,lg_prof_interval:32,lg_prof_sample:20,prof_prefix:jeprof.out" 

# 仅在执行我们的程序时,才注入jemalloc
LD_PRELOAD="/usr/local/lib/libjemalloc.so" <exec_name>

2.2 内存泄漏分析

内存泄漏分析与堆分析的使用方法差不多,首先进行配置,然后注入 jemalloc。

配置内容如下。

1
export MALLOC_CONF="prof_leak:true,lg_prof_sample:20,prof_final:true"

与堆分析的参数有两点区别。

  • prof_leak,用来分析内存泄露。
  • prof_final: true,在程序退出的时候生成一次 dump。

配置完毕后,使用 LD_PRELOAD 环境变量注入我们要执行的程序。执行完毕后生成相应的 dump 文件。

接下来使用 jeprof 工具进行分析。

1
./jeprof --lines --svg <exec_name> jeprof.heap > <exec_name>.svg

一个示例结果如下。

之前定位内存泄露总是使用 valgrind,但 valgrind 有着执行速度过慢以及内存占用内存过多的问题,而 jemalloc 则没有这个问题,后续再定位该类问题可以多试试 jemalloc 了。

三、使用问题

如果线上环境无法安装 graphviz gv 工具,那么可以使用 jeprof 生成 .dot 文件。

1
jeprof --lines --dot <exec_name>  --base jeprof.out.0.heap jeprof.out.3.heap > <exec_name>.dot

之后将 .dot 文件下载到有 graphviz 工具的服务上,执行命令生成 svg 文件。

1
dot -Tsvg <name>.dot -o <name>.svg

其他说明

jemalloc 统计的数据就是 new,malloc 函数传入参数指定的内存大小,但程序虽然申请了那么多内存,却不一定会用那么多,也因此系统不一定会分配那么多的物理内存。所以使用 jemalloc 分析内存时,可能与系统统计的 rss 内存不一致。这点要注意。