目前市面上有不少分析Jemalloc老版本的博文,但最新版本5.3.0却少之又少。而且5.3.0的架构与5之前的版本有较大不同,本着“与时俱进”、“由浅入深”的宗旨,我将逐步分析最新release版本Jemalloc5.3.0的实现。
另外,单讲实现代码是极其枯燥的,我将尽量每个原理知识点都用一个简简单单的小程序引出,这样便于大家测试和上手调试。另外,我还会用GDB打印数据结构、变量的值,方便理解当时的状态或算法。
本节我们的焦点是pa(page allocation)模块, pa是用来分配或释放一个extent(page-level的大块内存)。当一个extent没用时,并没有返给OS,而是极有可能缓存在了pa层。其对外的接口主要包括:
- pa_alloc: 获得一个extent
- pa_dalloc:释放一个extent
首先解释下一些源代码里的缩写:
缩写 | 全称(猜测) | 解释 |
---|---|---|
pa | page allocation | 模块-分配大于页的内存 |
pac | page allocation cache | 子模块-支持pa |
pai | page allocation interface | 子模块-支持pa |
eset | extent set | 200个paring heap, 每个都是对 相应大小的extent做缓存。 例如:eset.bins[0] 放4096字节的extent |
ecache | extent cache | |
edata | extent data | edata是对extent的描述 |
ph | pairing heap | 一个被jemalloc大量使用的数据结构 |
从ecache_retained.eset获得空闲的extent
从edata_cache.avail中获得空闲的edata_t
eset.bins[200]中下标与extent size的对应关系:
也就是说, eset.bins[0]存放的是一堆大小为4096字节的extent,eset.bins[1]存放的是一堆大小为8192字节的extent。。。
下面我简单举个例子说明arena.pa_shard.pac.eset.bins[x]是如何缓存一个空闲extent的。
在boot那一节中,有这样一个图:
注意红色部分,为了分配32768字节内存,实际分配了2M,这里就发生了extent split,分裂成了两个extent,分别由各自的edata_t描述。其中空闲的大小为2M-32768的那块由一个叫trail(临时变量名) 的edata_t描述(指向),它会被放入arena.pa_shard.pac.eset.bins[x]
如果你好奇怎么插入的,请看函数eset_insert:
好了,pa就到这里啦.