目前市面上有不少分析Jemalloc老版本的博文,但最新版本5.3.0却少之又少。而且5.3.0的架构与5之前的版本有较大不同,本着"与时俱进"、"由浅入深"的宗旨,我将逐步分析最新release版本Jemalloc5.3.0的实现。
另外,单讲实现代码是极其枯燥的,我将尽量每个原理知识点都用一个简简单单的小程序引出,这样便于大家测试和上手调试。另外,我还会用GDB打印数据结构、变量的值,方便理解当时的状态或算法。
jemalloc留了几个口子来配置参数,从而提高性能,我了解到的有以下四种:
- 编译选项
- 配置文件(链接) /etc/malloc.conf
- 环境变量 MALLOC_CONF
- 用户程序中调用mallctl动态配置
下面我详细介绍这四种配置方式,因为前面介绍了tcache,它默认是enabled的,本节我将分别用这几种配置方式disable tcache。
欲了解其它设置项请参考https://jemalloc.net/jemalloc.3.html
前三种方式,都是通过函数obtain_malloc_conf来拿到配置字符串的。
1. 编译选项
还记得编译那一篇中我们用了一个--enable-debug选项吗?
bash
./configure --enable-debug
configure脚本还支持很多选项,都列在了INSTALL.md中,其中有一个--with-malloc-conf可以用来配置参数。
bash
cd jemalloc-5.3.0
./configure --with-malloc-conf="tcache:false"
make
sudo make install
像这样就会关闭tcache功能。
用户所给出的"tcache:false"会作为全局变量config_malloc_conf的初始值。
config_malloc_conf中tcache的值false会赋给全局变量opt_tcache以供后来使用
用户的输入已传递到opt_tcache:
之后调用如下函数在tsd中设置tcache_enabled=flase (实际为设置tsd->cant_access_tsd_items_directly_use_a_getter_or_setter_tcache_enabled=false) 。
call stack:
总结一下,数据流向为:./configure --with-malloc-conf="tcache:false" => config_malloc_conf => opt_tcache => tsd
2. 配置文件(链接) /etc/malloc.conf
bash
ln -sf 'tcache:false' /etc/malloc.conf
执行 以上命令,/etc/malloc.conf的链接内容就变成了tcache:false, 注意:不是指向文件。false会先赋给全局变量opt_tcache,与第一种方式一样之后传给tsd。
3. 环境变量 MALLOC_CONF
环境变量可以设置全局的也可以设置临时的,临时的如下:
bash
MALLOC_CONF="tcache:false" ./a.out
获得环境变量值的代码如下:
之后也是把值赋值给opt_tcache, 与第一种方式一样之后传给tsd。
4. 用户程序中调用mallctl动态配置
前面的办法对一个程序来讲是静态的,一旦设定,程序中不能更改。与之相反,mallctl函数允许编程者在运行中动态改变参数值。看下面的例子。
cpp
$ cat disable_tcache.c
#include <jemalloc/jemalloc.h>
#include <stdbool.h>
#include <stdio.h>
void disable_tcache() {
bool tcache_enabled = false;
size_t sz = sizeof(tcache_enabled);
if (mallctl("thread.tcache.enabled", NULL, NULL, &tcache_enabled, sz) != 0) {
perror("Error disabling tcache");
}
}
int main() {
void *ptr1 = malloc(100); //默认tcache enabled
disable_tcache(); //关闭tcache
void *ptr2 = malloc(200); //tcache disabled.
return 0;
}
实现代码比较直接,都是mallctl调用je_ctl_byname处理不同的设置项的,本例的设置项为"thread.tcache.enabled"。