九浅一深Jemalloc5.3.0 -- ③浅*tcache

发布于:2024-07-02 ⋅ 阅读:(7) ⋅ 点赞:(0)

目前市面上有不少分析Jemalloc老版本的博文,但最新版本5.3.0却少之又少。而且5.3.0的架构与5之前的版本有较大不同,本着“与时俱进”、“由浅入深”的宗旨,我将逐步分析最新release版本Jemalloc5.3.0的实现。

另外,单讲实现代码是极其枯燥的,我将尽量每个原理知识点都用一个简简单单的小程序引出,这样便于大家测试和上手调试。另外,我还会用GDB打印数据结构、变量的值,方便理解当时的状态或算法。

为了减少不同线程间的竞争,Jemalloc为每个线程配备了其专属的“布袋”(tcache,估计是thread cache的缩写)用来缓存一些立即可用的内存,而且布袋又分成了很多隔间(bin数组)用来区分不同大小的内存,比如bins[0]是8个字节大小的空闲内存,bins[1]是16个字节大小的空闲内存。。。,还是上节size class的那套。

注意: 此处的bins类型为cache_bin_t, 与arena_t中的bins类型bin_t不同。

来一个小程序试试手

//gcc tcache.c `jemalloc-config --libdir`/libjemalloc.a `jemalloc-config --libs` -g
#include <malloc.h>
#include <stdlib.h>
#include <string.h>


int main(int argc, char* argv[])
{
        void *p1= malloc(10);
        memset(p1,'a',10);
        void *p2=malloc(10);
        memset(p2,'b',10);

        free(p1);
        free(p2);

        return 0;
}

在第二个malloc下断点(第一个malloc比较复杂,需要先给tcache.bin[1]填充一梭子弹药,第二个malloc只需直接取子弹),慢慢单步

 让我们先直接看看用户是怎么得到内存的:361行ret就是返给用户的内存地址(p2, 我的机器上是0x7ffff741d010), stack_head中藏着重点。说句题外话:stack_head-1指向的内存值就是p1(已被使用)。

下面让我们把stack_head, stack_head-1指向的内存的值打出来。

 看着熟悉吧,分别是第一次和第二次malloc返给用户的结果。

可以想像,当free p1时是反向操作,即:stack_head往小(地址)方向移动,并把要释放的内存的地址赋给stack_head指向的格子。

cache_bin_alloc/cache_bin_dalloc都只是挪了下stack_head而已。请看下图理解这些过程。

 

好了,因为是“浅”说,就点到为止吧。