前面没有分析完 Jemalloc 初始化,是因为遇到了一个表不得其解,所以停下来分析,这是一个精妙的算法,通过index可以算出size,通过size也可以算出index。
我是从size推算index开始研究的
注释的数是在以下推导的基础上填的
#define SIZE_CLASSES \
/* index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup */ \
SC( 0, 3, 3, 0, yes, 3) \ 1-8
SC( 1, 3, 3, 1, yes, 3) \ 9-16
SC( 2, 3, 3, 2, yes, 3) \ 17-24
SC( 3, 3, 3, 3, yes, 3) \ 25-32
\---------------------分割线以下适合用公式
SC( 4, 5, 3, 1, yes, 3) \ 33-40
SC( 5, 5, 3, 2, yes, 3) \ 41-48
SC( 6, 5, 3, 3, yes, 3) \ 49-56
SC( 7, 5, 3, 4, yes, 3) \ 57-64
\
SC( 8, 6, 4, 1, yes, 4) \ 65-80 size
SC( 9, 6, 4, 2, yes, 4) \ 81-96 size
SC( 10, 6, 4, 3, yes, 4) \ 97-112
SC( 11, 6, 4, 4, yes, 4) \ 113-128
\
SC( 12, 7, 5, 1, yes, 5) \ 129-160
SC( 13, 7, 5, 2, yes, 5) \ 161-192
SC( 14, 7, 5, 3, yes, 5) \ 193-224
SC( 15, 7, 5, 4, yes, 5) \ 225-256
\
SC( 16, 8, 6, 1, yes, 6) \
SC( 17, 8, 6, 2, yes, 6) \
SC( 18, 8, 6, 3, yes, 6) \
SC( 19, 8, 6, 4, yes, 6) \
\
SC( 20, 9, 7, 1, yes, 7) \
SC( 21, 9, 7, 2, yes, 7) \
SC( 22, 9, 7, 3, yes, 7) \
SC( 23, 9, 7, 4, yes, 7) \
\
SC( 24, 10, 8, 1, yes, 8) \
SC( 25, 10, 8, 2, yes, 8) \
SC( 26, 10, 8, 3, yes, 8) \
SC( 27, 10, 8, 4, yes, 8) \
\
SC( 28, 11, 9, 1, yes, 9) \
SC( 29, 11, 9, 2, yes, 9) \
SC( 30, 11, 9, 3, yes, 9) \
SC( 31, 11, 9, 4, yes, 9) \
\
SC( 32, 12, 10, 1, yes, no) \
SC( 33, 12, 10, 2, yes, no) \
SC( 34, 12, 10, 3, yes, no) \
SC( 35, 12, 10, 4, yes, no) \
\
SC( 36, 13, 11, 1, yes, no) \ 2^13 + 1,2^13 + 1 + 2^11-1=2^13 + 2^11
SC( 37, 13, 11, 2, yes, no) \ 2^13 + 2^11 + 1, 2^13 + 2^11 + 1 + 2^11 - 1 = 2^13 + 2*2^11
SC( 38, 13, 11, 3, yes, no) \ 2^13 + 2*2^11 + 1, 2^13 + 3*2^11
SC( 39, 13, 11, 4, no, no) \ 2^13 + 3*2^11 +1, 2^13 + 4*2^11 = 2^14
size2index
LOOKUP_MAXCLASS = 4096,4096以内的size才能直接在这个表里查找,否则就是计算
size2index_tab总数是8 + 4*2 + 4*2*2 + ... + 4*2^6 = 512
const uint8_t size2index_tab[] = {
(1,2,...7)
(8,8, 9,9, ..., 11,11)
(12,12,12,12, ...., 15,15,15,15)
...
(64个28, ..., 64个31)
}
size_t ret = ((size_t)(size2index_tab[(size-1) >> LG_TINY_MIN]));
索引(size-1) >> LG_TINY_MIN = (size-1) >> 3最大不会超过512
/* sizeof(void *) == 2^LG_SIZEOF_PTR. */ 3 = log2(8) 2 = log2(4)
#define LG_SIZEOF_PTR 3
/*
* Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size
* classes).
*/
#define LG_QUANTUM 3
size2index_compute(size_t size)
size_t x = unlikely(ZI(size) < 0) ? ((size<<1) ?
(ZU(1)<<(LG_SIZEOF_PTR+3)) : ((ZU(1)<<(LG_SIZEOF_PTR+3))-1))
: lg_floor((size<<1)-1);
size的二进制表示最高位1是第几位,x的含义就是grp
size_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 :
x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM);
x = 4是个分界点, x = 4能代表的最大数是5个1,即2^5 - 1 = 31
即如果size < 32, shift = 0,否则shift = x - 5,32 < size <= 64, shift = 1
size_t grp = shift << LG_SIZE_CLASS_GROUP;
如果size = 33~64,x = 6,shift = 1,grp = 2^2
如果size = 65~128,x = 7,shift = 2,grp = 2 * 2^2
如果size = 129~256,x = 8,shift = 3,grp = 3 * 2^2
size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1;
size <= 32, lg_delta = 3
size <= 64,x = 6, lg_delta = 3
size <= 128, x = 7, lg_delta = 4
size <= 256, x = 8, lg_delta = 5
size_t delta_inverse_mask = ZI(-1) << lg_delta;
size_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) &
((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
size = 64,lg_delta = 3, 减一去掉低(3, 4, 5...)位并右移,只取低2位,3
size = 65,lg_delta = 4, 减一去掉低(3, 4, 5...)位并右移,只取低2位,0
...
size_t index = NTBINS + grp + mod;
NTBINS = 0, 实际index = grp + mod
size = 64,4 + 3 = 7
size = 65, 8 + 0 = 8, 66, 8 +0 = 8,...,80, 8 + 0 = 8, [65-80] 这16个数共享8这个index
[81-96]这16个数共享9,[65-128]总共64,分成4组,共享4个index
[129-256]有128个数,划分成每份32,也是4组,[129-160]共享12,依次类推
结合上面的表可知各字段的含义
index:表中的索引
lg_grp:size-1的最高位1是第几位,从右往左数,从0开始
lg_delta:2^lg_delta个数共享1个index
ndelta:组内几个偏移单位
通过size可以计算出grp和mod,加和为index
下面分析index2size
通过index计算size也有一张表,他里面的size是代表这个index的最大size(结合上面表中添加的注释可以知道)
index2size_tab = {8, 16, 24, 32, 40, 48, 56, 64, 80, 96, ...
计算方法((ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta)),即2^lg_grp + ndelta * 2^lg_delta
但这是知道lg_grp和lg_delta,以及ndelta的前提下可以快速计算的,通过一个index能不能计算呢
通过index,不查表,也可以计算出grp和mod
因为index的后两位是mod,前面的是grp
size_t reduced_index = index - NTBINS;
size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP; 这里的grp是上面的shift
size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
index= 0,grp=0,mod=0
index= 1,grp=0,mod=1
index= 2,grp=0,mod=2
index= 3,grp=0,mod=3
index= 4,grp=1,mod=0
index= 5,grp=1,mod=1
index= 6,grp=1,mod=2
index= 7,grp=1,mod=3
index= 8,grp=2,mod=0
index= 9,grp=2,mod=1
....
size_t grp_size_mask = ~((!!grp)-1);
size_t grp_size = ((ZU(1) << (LG_QUANTUM + (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask;
index= 0,grp_size_mask=0x0, grp_size= 0
index= 1,grp_size_mask=0x0, grp_size= 0
index= 2,grp_size_mask=0x0, grp_size= 0
index= 3,grp_size_mask=0x0, grp_size= 0
index= 4,grp_size_mask=0xffffffff, grp_size= 32
index= 5,grp_size_mask=0xffffffff, grp_size= 32
index= 6,grp_size_mask=0xffffffff, grp_size= 32
index= 7,grp_size_mask=0xffffffff, grp_size= 32
index= 8,grp_size_mask=0xffffffff, grp_size= 64
index= 9,grp_size_mask=0xffffffff, grp_size= 64
....
size_t shift = (grp == 0) ? 1 : grp;
size_t lg_delta = shift + (LG_QUANTUM-1);
size_t mod_size = (mod+1) << lg_delta;
index= 0,shift=1, lg_delta=3 , mod_size=8
index= 1,shift=1, lg_delta=3 , mod_size=16
index= 2,shift=1, lg_delta=3 , mod_size=24
index= 3,shift=1, lg_delta=3 , mod_size=32
index= 4,shift=1, lg_delta=3 , mod_size=8
index= 5,shift=1, lg_delta=3 , mod_size=16
index= 6,shift=1, lg_delta=3 , mod_size=24
index= 7,shift=1, lg_delta=3 , mod_size=32
index= 8,shift=2, lg_delta=4 , mod_size=16
index= 9,shift=2, lg_delta=4 , mod_size=32
....
size_t usize = grp_size + mod_size;
index= 0,size=8
index= 1,size=16
index= 2,size=24
index= 3,size=32
index= 4,size=32 + 8=40
index= 5,size=32 + 16 = 48
index= 6,size=32 + 24 = 56
index= 7,size=32 + 32 = 64
index= 8,size=64 + 16 = 80
index= 9,size=64 + 32 = 96
....
还有个函数s2u_compute,他的结果是index2size_lookup的结果,即一个分组的内部分组的最大值
s2u_compute(35584)
size_t x = unlikely(ZI(size) < 0) ? ((size<<1) ?
(ZU(1)<<(LG_SIZEOF_PTR+3)) : ((ZU(1)<<(LG_SIZEOF_PTR+3))-1))
: lg_floor((size<<1)-1); //16
size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; //13
size_t delta = ZU(1) << lg_delta;
size_t delta_mask = delta - 1; //13个1
size_t usize = (size + delta_mask) & ~delta_mask; // 13位对齐,2^13大小对齐
return (usize);
以下面这组数据为例
SC( 4, 5, 3, 1, yes, 3) \ 33-40,33-39都让它变成40(按8字节对齐)
SC( 5, 5, 3, 2, yes, 3) \ 41-48
SC( 6, 5, 3, 3, yes, 3) \ 49-56
SC( 7, 5, 3, 4, yes, 3) \ 57-64