/*
* Read-only information associated with each element of arena_t's bins array
* is stored separately, partly to reduce memory usage (only one copy, rather
* than one per arena), but mainly to avoid false cacheline sharing.
* 和arena_t的bins数组的每个元素关联的只读信息,是单独存储的,部分目的是缩减内存使用,而不是每个area都拷贝一份
主要是因为避免cache对齐共享错误
* Each run has the following layout: 每个run(一个run可以理解成一片可使用的内存(large,多页,small,一页))都是如下布局
*
* /--------------------\
* | pad? |
* |--------------------|
* | redzone |
* reg0_offset | region 0 |
* | redzone |
* |--------------------| \
* | redzone | |
* | region 1 | > reg_interval
* | redzone | /
* |--------------------|
* | ... |
* | ... |
* | ... |
* |--------------------|
* | redzone |
* | region nregs-1 |
* | redzone |
* |--------------------|
* | alignment pad? |
* \--------------------/
*
* reg_interval has at least the same minimum alignment as reg_size; this
* preserves the alignment constraint that sa2u() depends on. Alignment pad is
* either 0 or redzone_size; it is present only if needed to align reg0_offset.
*/
reg_interval(reg间距)至少要按照reg_size的最小值对齐,sa2u依赖这一预留的对齐约束
对齐填充(alignment pad)可以是0或者redzone_size,仅在需要和reg0_offset对齐时才需要
struct arena_bin_info_s {
/* Size of regions in a run for this bin's size class. */
size_t reg_size;在一个run中为这个bin的大小类规定的region大小(参加SIZE_CLASS表)
/* Redzone size. */
size_t redzone_size; 调试观察,是0
/* Interval between regions (reg_size + (redzone_size << 1)). */
size_t reg_interval;这里等于reg_size
/* Total size of a run for this bin's size class. */
size_t run_size;为这个bin的大小类规定的run size有多大
/* Total number of regions in a run for this bin's size class. */
uint32_t nregs; 在为这个bin的大小类规定的run中有几个region
/*
* Metadata used to manipulate bitmaps for runs associated with this
* bin.
*/用来操作(run和这个run关联的bins的)位图的元数据
bitmap_info_t bitmap_info;
/* Offset of first region in a run for this bin's size class. */
uint32_t reg0_offset;为这个bin的大小类规定的run中,第一个region的偏移,调试看都是0
};
struct bitmap_level_s {
/* Offset of this level's groups within the array of groups. */
size_t group_offset;
};
struct bitmap_info_s {
/* Logical number of bits in bitmap (stored at bottom level). */
size_t nbits; 在位图中bits的逻辑数
/* Number of levels necessary for nbits. */
unsigned nlevels;对于nbits必须的levels数量
/*
* Only the first (nlevels+1) elements are used, and levels are ordered
* bottom to top (e.g. the bottom level is stored in levels[0]).
*/只有第一个元素(nlevels+1)被使用4,leves排序从低到高,
bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; 3 + 1 = 4
#define LG_RUN_MAXREGS (LG_PAGE - LG_TINY_MIN) 12 - 3
#define LG_BITMAP_MAXBITS LG_RUN_MAXREGS 9
#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) 512
/* Maximum number of levels possible. */ 最大可能的层数
#define BITMAP_MAX_LEVELS \
(LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ (9/3+0)=3
+ !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) 有余数加1,没余数加0
64位一个long,定为1个组,可以表示64个region,实际情况是最多512个region,
至少需要8个long,这一层是最低层,也就是最低层有8个group
这8个group需要管理,来判断某个group是不是满了,8个位就够了,1个long更绰绰有余
所以就有了第二层1个long
(这里设想一下多层的情况,假设需要表示64*128 = 8192个region,需要128个long,
也就是底层128个group,第二层要管理128个group,需要2个long,即第二层有2个group
(中间group,一位表示底层的一个group是否满),根据下面的bitmap_info_init函数,
只要group_count > 1就循环设置上一层,于是有了第三层,第三层1个long就可以管理2个group)
下面的宏充分说明了计算方式
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 表示的个数小于等于4096
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS)
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 表示的个数 (4096, 256 * 1024)
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS)
那么怎么计算层数呢,跟要表示的数的个数有关
小于等于64(6),1层
小于等于4096(12),2层
小于等于256*1024(18),3层
直观看就是6/6, 12/6, 18/6,刚好就是上面的对数相除
};
初始化,再研究bin_info_init
static void
bin_info_init(void)
{
arena_bin_info_t *bin_info;
#define BIN_INFO_INIT_bin_yes(index, size) \
bin_info = &arena_bin_info[index]; \
bin_info->reg_size = size; \ 根据表计算
bin_info_run_size_calc(bin_info); \
bitmap_info_init(&bin_info->bitmap_info, bin_info->nregs);
#define BIN_INFO_INIT_bin_no(index, size)
#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
BIN_INFO_INIT_bin_##bin(index, (ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta))
函数内定义了局部的SC,定义内容也是一个宏,BIN_INFO_INIT_bin_yes或者BIN_INFO_INIT_bin_no
SIZE_CLASSES
这个单词就是宏展开的地方,如果bin的那一项是yes的话,就调用BIN_INFO_INIT_bin_yes展开
index = binind, size = 2^lg_grp + 2^lg_delta, 是一个组的某一项代表的大小区间的最大值
#undef BIN_INFO_INIT_bin_yes
#undef BIN_INFO_INIT_bin_no
#undef SC
}
分析bin_info_run_size_calc
/* 计算满足以下约束的bin_info->run_size
* Calculate bin_info->run_size such that it meets the following constraints:
*
* *) bin_info->run_size <= arena_maxrun 小于等于je_arena_maxrun = 0x1f3000,
这个大小是刚分配一个chunk(2M),并放完chunk的meta信息后剩余的大小
* *) bin_info->nregs <= RUN_MAXREGS
#define RUN_MAXREGS (1U << LG_RUN_MAXREGS) 512
*
* bin_info->nregs and bin_info->reg0_offset are also calculated here, since
* these settings are all interdependent. 这些设置都是内部互相依赖的
*/
static void
bin_info_run_size_calc(arena_bin_info_t *bin_info)
{
size_t pad_size;
size_t try_run_size, perfect_run_size, actual_run_size;
uint32_t try_nregs, perfect_nregs, actual_nregs;
if (config_fill && unlikely(opt_redzone)) {
...opt_redzone = false,这个分支没有走到
} else {
bin_info->redzone_size = 0;
pad_size = 0;
}
bin_info->reg_interval = bin_info->reg_size + (bin_info->redzone_size << 1);
reg_interval == reg_size
/*
* Compute run size under ideal conditions (no redzones, no limit on run
* size).在理想情况下计算run size,不考虑redzones,run_size的大小
*/
try_run_size = PAGE;
try_nregs = try_run_size / bin_info->reg_size;
do {
perfect_run_size = try_run_size;
perfect_nregs = try_nregs;
try_run_size += PAGE;
try_nregs = try_run_size / bin_info->reg_size;
} while (perfect_run_size != perfect_nregs * bin_info->reg_size);
assert(perfect_nregs <= RUN_MAXREGS);
计算的准则是,run_size的大小能被reg_size整除
actual_run_size = perfect_run_size;
actual_nregs = (actual_run_size - pad_size) / bin_info->reg_interval; pad_size = 0
/*
* Redzones can require enough padding that not even a single region can
* fit within the number of pages that would normally be dedicated to a
* run for this size class. Increase the run size until at least one
* region fits.
*/
while (actual_nregs == 0) {
没走到
}
/*
* Make sure that the run will fit within an arena chunk.
*/确保这个run满足在一个chunk内
while (actual_run_size > arena_maxrun) {
。。。也没走到
}
assert(actual_nregs > 0);
assert(actual_run_size == s2u(actual_run_size));
reg_size符合s2u,actual_run_size又能被reg_size整除,所以也满足s2u
/* Copy final settings. */ 拷贝最终的设置
bin_info->run_size = actual_run_size;
bin_info->nregs = actual_nregs;
bin_info->reg0_offset = actual_run_size - (actual_nregs * bin_info->reg_interval) - pad_size + bin_info->redzone_size;
if (actual_run_size > small_maxrun) 如果某个run_size > je_small_maxrun,覆盖small_maxrun的值
small_maxrun = actual_run_size; small_maxrun存储的是最大的run_size,都运行完后是0x7000(7页)
。。。
}
void
bitmap_info_init(bitmap_info_t *binfo, size_t nbits) nbits = nregs,有多少个regions的意思
{
unsigned i;
size_t group_count;
assert(nbits > 0);
assert(nbits <= (ZU(1) << LG_BITMAP_MAXBITS)); 512
/*
* Compute the number of groups necessary to store nbits bits, and
* progressively work upward through the levels until reaching a level
* that requires only one group.
*/ 计算存储nbits个位(比如512位)需要多少个group,通过levels逐步向上工作,
直到达到仅需要一个group的水平
binfo->levels[0].group_offset = 0;
group_count = BITMAP_BITS2GROUPS(nbits); 8
/* Number of bits per group. */ 每组位的数量
#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) 3 + 3 = 6,一组能存储2^6位(64位)
#define BITMAP_GROUP_NBITS (ZU(1) << LG_BITMAP_GROUP_NBITS) 64位
#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1)
/* Number of groups required to store a given number of bits. */
#define BITMAP_BITS2GROUPS(nbits) \ 存储这么多位需要多少组
((nbits + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS)
如果要存储的位数不能被64整除,哪怕余数是1,group数量也增1
for (i = 1; group_count > 1; i++) { group_count > 1循环就继续, group_count初始值是8
assert(i < BITMAP_MAX_LEVELS); 意味着循环最多不超过2次(i=1,i=2)
binfo->levels[i].group_offset = binfo->levels[i-1].group_offset + group_count;
第一次,levels1.group_offset = 8
group_count = BITMAP_BITS2GROUPS(group_count);
第一次group_count = 1(8/64=0余8)
}
binfo->levels[i].group_offset = binfo->levels[i-1].group_offset + group_count;
levels2.group_offset = 8 + 1 = 9
assert(binfo->levels[i].group_offset <= BITMAP_GROUPS_MAX); 9
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2
9 <= 12
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS)
BITMAP_MAXBITS 1 << 9 = 512
BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)
BITMAP_GROUPS_L0(nbits) + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
BITMAP_BITS2GROUPS(nbits) + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
((nbits + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS)
(512 + 63) >> 6 = 8 (8 + 63) >> 6 = 1
8 + 1 = 9 这个运算和上面的循环是一样的
binfo->nlevels = i; 2,2层
binfo->nbits = nbits; 512
}
以上这些信息都是固定不变的,所有area共享
arena_bin_nonfull_run_get会调用je_bitmap_init
bitmap_init(run->bitmap, &bin_info->bitmap_info);
void
bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo)
{ bitmap需要设置,binfo是只读的
size_t extra;
unsigned i;
/*
* Bits are actually inverted with regard to the external bitmap
* interface, so the bitmap starts out with all 1 bits, except for
* trailing unused bits (if any). Note that each group uses bit 0 to
* correspond to the first logical bit in the group, so extra bits
* are the most significant bits of the last group.
*/
memset(bitmap, 0xffU, binfo->levels[binfo->nlevels].group_offset << LG_SIZEOF_BITMAP);
bitmap是long类型的数组(BITMAP_GROUPS_MAX),levels2.group_offset = 9,
9个long,9*8=72字节,每个字节都设置成-1
extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK;
如果binfo->nbits(512)不是按照64对齐的,extra就是(64 - 余数)
if (extra != 0)
bitmap[binfo->levels[1].group_offset - 1] >>= extra;
binind = 11,reg_size = 128
binfo = {nbits = 32, nlevels = 1, levels = {{group_offset = 0}, {group_offset = 1},
{group_offset = 0}, {group_offset = 0}}}
bitmap[0]右移32位
for (i = 1; i < binfo->nlevels; i++) {
size_t group_count = binfo->levels[i].group_offset - binfo->levels[i-1].group_offset;
8
extra = (BITMAP_GROUP_NBITS - (group_count & BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK;
if (extra != 0) 64 - 8
bitmap[binfo->levels[i+1].group_offset - 1] >>= extra;
bitmap[levels2.group_offset - 1] = bitmap[8] >>= 56
}
}
初始化完后bitmap数组(动态的)的内存布局
Low Address---->High Address(小端机器)
|ff...ff|ff...ff|ff...ff|ff...ff|ff...ff|ff...ff|ff...ff|ff...ff|ff00...00|
分配内存通过regind = bitmap_sfu(run->bitmap, &bin_info->bitmap_info);实现
得到regind,就可以通过
ret = (void *)((uintptr_t)rpages + (uintptr_t)bin_info->reg0_offset + (uintptr_t)(bin_info->reg_interval * regind)
得到要分配的地址
bitmap_info[0] = {nbits = 512, nlevels = 2,
levels = {{group_offset = 0}, {group_offset = 8}, {group_offset = 9}, {group_offset = 0}}}
JEMALLOC_INLINE size_t
bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo)
{
size_t bit;
bitmap_t g;
unsigned i;
assert(!bitmap_full(bitmap, binfo));
i = binfo->nlevels - 1; 1
g = bitmap[binfo->levels[i].group_offset]; 8
255,一个long是255,他的高位地址都被置0了
选定最顶层的那个long
bit = jemalloc_ffsl(g) - 1;
__builtin_ffsl,返回右起第一个1的位置,从1开始, 所以要减1
找到第一个空闲的group(最高层次的group)
while (i > 0) { 如果i == 0,说明得到的bit是代表某个位被使用,而不是某个组满了,这时就找了这个bit
i--;上来先降一个层次,到每个具体的group层
g = bitmap[binfo->levels[i].group_offset + bit]; 0 + 0
这一层的group在bitmap数组中的偏移 + 第一个空闲的group的偏移
得到目标group在bitmap数组中的偏移,通过bitmap数组得到目标long
bitmap[0] = -1
bit = (bit << LG_BITMAP_GROUP_NBITS) + (jemalloc_ffsl(g) - 1);
bit先表示第一个空闲的group的偏移,1个偏移是1个long
后来表示第一个空闲的group的第一个空闲位,代表的是第几个region
所以先用group乘以64,表示这个group表示的最小region,再加上group内部第一个1的偏移
得到最小的空闲region
0 + 0
}
bitmap_set(bitmap, binfo, bit);找到空闲的region id后,更改位图信息
return (bit); 返回0,作为reg的id
}
bitmap_sfu总结为一句话,自上而下查找空闲位
bitmap_set总结为一句话,自下而上置位
JEMALLOC_INLINE bool
bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo)
{
unsigned rgoff = binfo->levels[binfo->nlevels].group_offset - 1; 9 - 1
bitmap_t rg = bitmap[rgoff]; rgoff = 8
bitmap[8]初始化时右移了56位,还剩8个1,如果这8个1都置0了,就满了
/* The bitmap is full iff the root group is 0. */
return (rg == 0);
}
一个位被选中后,意味着一块内存被选中,下面是更改位图信息
JEMALLOC_INLINE void
bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
{
size_t goff;
bitmap_t *gp;
bitmap_t g;
assert(bit < binfo->nbits); 0 < 512
assert(!bitmap_get(bitmap, binfo, bit)); bit对应的那个位应该没有用过,是1
goff = bit >> LG_BITMAP_GROUP_NBITS;
gp = &bitmap[goff];
这里属于一级位图,goff直接作为索引
g = *gp;先找到bit对应的那个long
assert(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK))); bit对应的那个long的那个位是1
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);将bit对应的那个位设置成0,
其他位呢,以前使用的位是0,0和0异或,还是0,以前没使用的是1,1和0异或还是1,所以其他位保持不变
*gp = g;
assert(bitmap_get(bitmap, binfo, bit));确保bit那个位设置成0了
/* Propagate group state transitions up the tree. */ 向树的上方传播组的状态迁移
if (g == 0) { 如果这个组满了,所有位都置成0了
unsigned i;
for (i = 1; i < binfo->nlevels; i++) {
bit = goff;
goff = bit >> LG_BITMAP_GROUP_NBITS; 上面这两句可以合并goff = goff >> LG_BITMAP_GROUP_NBITS;
goff自己属于哪个long(bit原来属于goff这个long,goff属于哪个long呢,就属于现在的goff这个long)
gp = &bitmap[binfo->levels[i].group_offset + goff];
这是二级位图,二级以上的都加上了group_offset,8
g = *gp;
assert(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)));
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
*gp = g; 二级位图的含义是某个位代表某个group,置0,说明这个group满了
if (g != 0)
break;
}
}
}
JEMALLOC_INLINE bool
bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
{
size_t goff;
bitmap_t g;
assert(bit < binfo->nbits); 0 < 512
goff = bit >> LG_BITMAP_GROUP_NBITS; bit这个数对应哪个long
右移(LG_SIZEOF_BITMAP + 3)6位,512右移6为是8,511是7,这里是0
g = bitmap[goff]; -1
return (!(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK))));这个long的哪一位对应这个bit
bit对64取余数a,看g的第a位(从右从0开始)是1还是0,是1,返回0,是0,返回1
}
* Read-only information associated with each element of arena_t's bins array
* is stored separately, partly to reduce memory usage (only one copy, rather
* than one per arena), but mainly to avoid false cacheline sharing.
* 和arena_t的bins数组的每个元素关联的只读信息,是单独存储的,部分目的是缩减内存使用,而不是每个area都拷贝一份
主要是因为避免cache对齐共享错误
* Each run has the following layout: 每个run(一个run可以理解成一片可使用的内存(large,多页,small,一页))都是如下布局
*
* /--------------------\
* | pad? |
* |--------------------|
* | redzone |
* reg0_offset | region 0 |
* | redzone |
* |--------------------| \
* | redzone | |
* | region 1 | > reg_interval
* | redzone | /
* |--------------------|
* | ... |
* | ... |
* | ... |
* |--------------------|
* | redzone |
* | region nregs-1 |
* | redzone |
* |--------------------|
* | alignment pad? |
* \--------------------/
*
* reg_interval has at least the same minimum alignment as reg_size; this
* preserves the alignment constraint that sa2u() depends on. Alignment pad is
* either 0 or redzone_size; it is present only if needed to align reg0_offset.
*/
reg_interval(reg间距)至少要按照reg_size的最小值对齐,sa2u依赖这一预留的对齐约束
对齐填充(alignment pad)可以是0或者redzone_size,仅在需要和reg0_offset对齐时才需要
struct arena_bin_info_s {
/* Size of regions in a run for this bin's size class. */
size_t reg_size;在一个run中为这个bin的大小类规定的region大小(参加SIZE_CLASS表)
/* Redzone size. */
size_t redzone_size; 调试观察,是0
/* Interval between regions (reg_size + (redzone_size << 1)). */
size_t reg_interval;这里等于reg_size
/* Total size of a run for this bin's size class. */
size_t run_size;为这个bin的大小类规定的run size有多大
/* Total number of regions in a run for this bin's size class. */
uint32_t nregs; 在为这个bin的大小类规定的run中有几个region
/*
* Metadata used to manipulate bitmaps for runs associated with this
* bin.
*/用来操作(run和这个run关联的bins的)位图的元数据
bitmap_info_t bitmap_info;
/* Offset of first region in a run for this bin's size class. */
uint32_t reg0_offset;为这个bin的大小类规定的run中,第一个region的偏移,调试看都是0
};
struct bitmap_level_s {
/* Offset of this level's groups within the array of groups. */
size_t group_offset;
};
struct bitmap_info_s {
/* Logical number of bits in bitmap (stored at bottom level). */
size_t nbits; 在位图中bits的逻辑数
/* Number of levels necessary for nbits. */
unsigned nlevels;对于nbits必须的levels数量
/*
* Only the first (nlevels+1) elements are used, and levels are ordered
* bottom to top (e.g. the bottom level is stored in levels[0]).
*/只有第一个元素(nlevels+1)被使用4,leves排序从低到高,
bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; 3 + 1 = 4
#define LG_RUN_MAXREGS (LG_PAGE - LG_TINY_MIN) 12 - 3
#define LG_BITMAP_MAXBITS LG_RUN_MAXREGS 9
#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) 512
/* Maximum number of levels possible. */ 最大可能的层数
#define BITMAP_MAX_LEVELS \
(LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ (9/3+0)=3
+ !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) 有余数加1,没余数加0
64位一个long,定为1个组,可以表示64个region,实际情况是最多512个region,
至少需要8个long,这一层是最低层,也就是最低层有8个group
这8个group需要管理,来判断某个group是不是满了,8个位就够了,1个long更绰绰有余
所以就有了第二层1个long
(这里设想一下多层的情况,假设需要表示64*128 = 8192个region,需要128个long,
也就是底层128个group,第二层要管理128个group,需要2个long,即第二层有2个group
(中间group,一位表示底层的一个group是否满),根据下面的bitmap_info_init函数,
只要group_count > 1就循环设置上一层,于是有了第三层,第三层1个long就可以管理2个group)
下面的宏充分说明了计算方式
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 表示的个数小于等于4096
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS)
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 表示的个数 (4096, 256 * 1024)
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS)
那么怎么计算层数呢,跟要表示的数的个数有关
小于等于64(6),1层
小于等于4096(12),2层
小于等于256*1024(18),3层
直观看就是6/6, 12/6, 18/6,刚好就是上面的对数相除
};
初始化,再研究bin_info_init
static void
bin_info_init(void)
{
arena_bin_info_t *bin_info;
#define BIN_INFO_INIT_bin_yes(index, size) \
bin_info = &arena_bin_info[index]; \
bin_info->reg_size = size; \ 根据表计算
bin_info_run_size_calc(bin_info); \
bitmap_info_init(&bin_info->bitmap_info, bin_info->nregs);
#define BIN_INFO_INIT_bin_no(index, size)
#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
BIN_INFO_INIT_bin_##bin(index, (ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta))
函数内定义了局部的SC,定义内容也是一个宏,BIN_INFO_INIT_bin_yes或者BIN_INFO_INIT_bin_no
SIZE_CLASSES
这个单词就是宏展开的地方,如果bin的那一项是yes的话,就调用BIN_INFO_INIT_bin_yes展开
index = binind, size = 2^lg_grp + 2^lg_delta, 是一个组的某一项代表的大小区间的最大值
#undef BIN_INFO_INIT_bin_yes
#undef BIN_INFO_INIT_bin_no
#undef SC
}
分析bin_info_run_size_calc
/* 计算满足以下约束的bin_info->run_size
* Calculate bin_info->run_size such that it meets the following constraints:
*
* *) bin_info->run_size <= arena_maxrun 小于等于je_arena_maxrun = 0x1f3000,
这个大小是刚分配一个chunk(2M),并放完chunk的meta信息后剩余的大小
* *) bin_info->nregs <= RUN_MAXREGS
#define RUN_MAXREGS (1U << LG_RUN_MAXREGS) 512
*
* bin_info->nregs and bin_info->reg0_offset are also calculated here, since
* these settings are all interdependent. 这些设置都是内部互相依赖的
*/
static void
bin_info_run_size_calc(arena_bin_info_t *bin_info)
{
size_t pad_size;
size_t try_run_size, perfect_run_size, actual_run_size;
uint32_t try_nregs, perfect_nregs, actual_nregs;
if (config_fill && unlikely(opt_redzone)) {
...opt_redzone = false,这个分支没有走到
} else {
bin_info->redzone_size = 0;
pad_size = 0;
}
bin_info->reg_interval = bin_info->reg_size + (bin_info->redzone_size << 1);
reg_interval == reg_size
/*
* Compute run size under ideal conditions (no redzones, no limit on run
* size).在理想情况下计算run size,不考虑redzones,run_size的大小
*/
try_run_size = PAGE;
try_nregs = try_run_size / bin_info->reg_size;
do {
perfect_run_size = try_run_size;
perfect_nregs = try_nregs;
try_run_size += PAGE;
try_nregs = try_run_size / bin_info->reg_size;
} while (perfect_run_size != perfect_nregs * bin_info->reg_size);
assert(perfect_nregs <= RUN_MAXREGS);
计算的准则是,run_size的大小能被reg_size整除
actual_run_size = perfect_run_size;
actual_nregs = (actual_run_size - pad_size) / bin_info->reg_interval; pad_size = 0
/*
* Redzones can require enough padding that not even a single region can
* fit within the number of pages that would normally be dedicated to a
* run for this size class. Increase the run size until at least one
* region fits.
*/
while (actual_nregs == 0) {
没走到
}
/*
* Make sure that the run will fit within an arena chunk.
*/确保这个run满足在一个chunk内
while (actual_run_size > arena_maxrun) {
。。。也没走到
}
assert(actual_nregs > 0);
assert(actual_run_size == s2u(actual_run_size));
reg_size符合s2u,actual_run_size又能被reg_size整除,所以也满足s2u
/* Copy final settings. */ 拷贝最终的设置
bin_info->run_size = actual_run_size;
bin_info->nregs = actual_nregs;
bin_info->reg0_offset = actual_run_size - (actual_nregs * bin_info->reg_interval) - pad_size + bin_info->redzone_size;
if (actual_run_size > small_maxrun) 如果某个run_size > je_small_maxrun,覆盖small_maxrun的值
small_maxrun = actual_run_size; small_maxrun存储的是最大的run_size,都运行完后是0x7000(7页)
。。。
}
void
bitmap_info_init(bitmap_info_t *binfo, size_t nbits) nbits = nregs,有多少个regions的意思
{
unsigned i;
size_t group_count;
assert(nbits > 0);
assert(nbits <= (ZU(1) << LG_BITMAP_MAXBITS)); 512
/*
* Compute the number of groups necessary to store nbits bits, and
* progressively work upward through the levels until reaching a level
* that requires only one group.
*/ 计算存储nbits个位(比如512位)需要多少个group,通过levels逐步向上工作,
直到达到仅需要一个group的水平
binfo->levels[0].group_offset = 0;
group_count = BITMAP_BITS2GROUPS(nbits); 8
/* Number of bits per group. */ 每组位的数量
#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) 3 + 3 = 6,一组能存储2^6位(64位)
#define BITMAP_GROUP_NBITS (ZU(1) << LG_BITMAP_GROUP_NBITS) 64位
#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1)
/* Number of groups required to store a given number of bits. */
#define BITMAP_BITS2GROUPS(nbits) \ 存储这么多位需要多少组
((nbits + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS)
如果要存储的位数不能被64整除,哪怕余数是1,group数量也增1
for (i = 1; group_count > 1; i++) { group_count > 1循环就继续, group_count初始值是8
assert(i < BITMAP_MAX_LEVELS); 意味着循环最多不超过2次(i=1,i=2)
binfo->levels[i].group_offset = binfo->levels[i-1].group_offset + group_count;
第一次,levels1.group_offset = 8
group_count = BITMAP_BITS2GROUPS(group_count);
第一次group_count = 1(8/64=0余8)
}
binfo->levels[i].group_offset = binfo->levels[i-1].group_offset + group_count;
levels2.group_offset = 8 + 1 = 9
assert(binfo->levels[i].group_offset <= BITMAP_GROUPS_MAX); 9
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2
9 <= 12
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS)
BITMAP_MAXBITS 1 << 9 = 512
BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)
BITMAP_GROUPS_L0(nbits) + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
BITMAP_BITS2GROUPS(nbits) + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
((nbits + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS)
(512 + 63) >> 6 = 8 (8 + 63) >> 6 = 1
8 + 1 = 9 这个运算和上面的循环是一样的
binfo->nlevels = i; 2,2层
binfo->nbits = nbits; 512
}
以上这些信息都是固定不变的,所有area共享
arena_bin_nonfull_run_get会调用je_bitmap_init
bitmap_init(run->bitmap, &bin_info->bitmap_info);
void
bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo)
{ bitmap需要设置,binfo是只读的
size_t extra;
unsigned i;
/*
* Bits are actually inverted with regard to the external bitmap
* interface, so the bitmap starts out with all 1 bits, except for
* trailing unused bits (if any). Note that each group uses bit 0 to
* correspond to the first logical bit in the group, so extra bits
* are the most significant bits of the last group.
*/
memset(bitmap, 0xffU, binfo->levels[binfo->nlevels].group_offset << LG_SIZEOF_BITMAP);
bitmap是long类型的数组(BITMAP_GROUPS_MAX),levels2.group_offset = 9,
9个long,9*8=72字节,每个字节都设置成-1
extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK;
如果binfo->nbits(512)不是按照64对齐的,extra就是(64 - 余数)
if (extra != 0)
bitmap[binfo->levels[1].group_offset - 1] >>= extra;
binind = 11,reg_size = 128
binfo = {nbits = 32, nlevels = 1, levels = {{group_offset = 0}, {group_offset = 1},
{group_offset = 0}, {group_offset = 0}}}
bitmap[0]右移32位
for (i = 1; i < binfo->nlevels; i++) {
size_t group_count = binfo->levels[i].group_offset - binfo->levels[i-1].group_offset;
8
extra = (BITMAP_GROUP_NBITS - (group_count & BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK;
if (extra != 0) 64 - 8
bitmap[binfo->levels[i+1].group_offset - 1] >>= extra;
bitmap[levels2.group_offset - 1] = bitmap[8] >>= 56
}
}
初始化完后bitmap数组(动态的)的内存布局
Low Address---->High Address(小端机器)
|ff...ff|ff...ff|ff...ff|ff...ff|ff...ff|ff...ff|ff...ff|ff...ff|ff00...00|
分配内存通过regind = bitmap_sfu(run->bitmap, &bin_info->bitmap_info);实现
得到regind,就可以通过
ret = (void *)((uintptr_t)rpages + (uintptr_t)bin_info->reg0_offset + (uintptr_t)(bin_info->reg_interval * regind)
得到要分配的地址
bitmap_info[0] = {nbits = 512, nlevels = 2,
levels = {{group_offset = 0}, {group_offset = 8}, {group_offset = 9}, {group_offset = 0}}}
JEMALLOC_INLINE size_t
bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo)
{
size_t bit;
bitmap_t g;
unsigned i;
assert(!bitmap_full(bitmap, binfo));
i = binfo->nlevels - 1; 1
g = bitmap[binfo->levels[i].group_offset]; 8
255,一个long是255,他的高位地址都被置0了
选定最顶层的那个long
bit = jemalloc_ffsl(g) - 1;
__builtin_ffsl,返回右起第一个1的位置,从1开始, 所以要减1
找到第一个空闲的group(最高层次的group)
while (i > 0) { 如果i == 0,说明得到的bit是代表某个位被使用,而不是某个组满了,这时就找了这个bit
i--;上来先降一个层次,到每个具体的group层
g = bitmap[binfo->levels[i].group_offset + bit]; 0 + 0
这一层的group在bitmap数组中的偏移 + 第一个空闲的group的偏移
得到目标group在bitmap数组中的偏移,通过bitmap数组得到目标long
bitmap[0] = -1
bit = (bit << LG_BITMAP_GROUP_NBITS) + (jemalloc_ffsl(g) - 1);
bit先表示第一个空闲的group的偏移,1个偏移是1个long
后来表示第一个空闲的group的第一个空闲位,代表的是第几个region
所以先用group乘以64,表示这个group表示的最小region,再加上group内部第一个1的偏移
得到最小的空闲region
0 + 0
}
bitmap_set(bitmap, binfo, bit);找到空闲的region id后,更改位图信息
return (bit); 返回0,作为reg的id
}
bitmap_sfu总结为一句话,自上而下查找空闲位
bitmap_set总结为一句话,自下而上置位
JEMALLOC_INLINE bool
bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo)
{
unsigned rgoff = binfo->levels[binfo->nlevels].group_offset - 1; 9 - 1
bitmap_t rg = bitmap[rgoff]; rgoff = 8
bitmap[8]初始化时右移了56位,还剩8个1,如果这8个1都置0了,就满了
/* The bitmap is full iff the root group is 0. */
return (rg == 0);
}
一个位被选中后,意味着一块内存被选中,下面是更改位图信息
JEMALLOC_INLINE void
bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
{
size_t goff;
bitmap_t *gp;
bitmap_t g;
assert(bit < binfo->nbits); 0 < 512
assert(!bitmap_get(bitmap, binfo, bit)); bit对应的那个位应该没有用过,是1
goff = bit >> LG_BITMAP_GROUP_NBITS;
gp = &bitmap[goff];
这里属于一级位图,goff直接作为索引
g = *gp;先找到bit对应的那个long
assert(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK))); bit对应的那个long的那个位是1
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);将bit对应的那个位设置成0,
其他位呢,以前使用的位是0,0和0异或,还是0,以前没使用的是1,1和0异或还是1,所以其他位保持不变
*gp = g;
assert(bitmap_get(bitmap, binfo, bit));确保bit那个位设置成0了
/* Propagate group state transitions up the tree. */ 向树的上方传播组的状态迁移
if (g == 0) { 如果这个组满了,所有位都置成0了
unsigned i;
for (i = 1; i < binfo->nlevels; i++) {
bit = goff;
goff = bit >> LG_BITMAP_GROUP_NBITS; 上面这两句可以合并goff = goff >> LG_BITMAP_GROUP_NBITS;
goff自己属于哪个long(bit原来属于goff这个long,goff属于哪个long呢,就属于现在的goff这个long)
gp = &bitmap[binfo->levels[i].group_offset + goff];
这是二级位图,二级以上的都加上了group_offset,8
g = *gp;
assert(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)));
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
*gp = g; 二级位图的含义是某个位代表某个group,置0,说明这个group满了
if (g != 0)
break;
}
}
}
JEMALLOC_INLINE bool
bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit)
{
size_t goff;
bitmap_t g;
assert(bit < binfo->nbits); 0 < 512
goff = bit >> LG_BITMAP_GROUP_NBITS; bit这个数对应哪个long
右移(LG_SIZEOF_BITMAP + 3)6位,512右移6为是8,511是7,这里是0
g = bitmap[goff]; -1
return (!(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK))));这个long的哪一位对应这个bit
bit对64取余数a,看g的第a位(从右从0开始)是1还是0,是1,返回0,是0,返回1
}