jemalloc横向分析(六)tcache_event事件执行
来源:互联网 发布:剑灵召唤师女捏脸数据 编辑:程序博客网 时间:2024/05/29 16:12
tcache_alloc_small最后调用了tcache_event
里面tcache->ev_cnt++;
当tcache->ev_cnt == TCACHE_GC_INCR(211)时
/*
* TCACHE_GC_SWEEP is the approximate number of allocation events between
* full GC sweeps. Integer rounding may cause the actual number to be
* slightly higher, since GC is performed incrementally.
*/
#define TCACHE_GC_SWEEP 8192
/* Number of tcache allocation/deallocation events between incremental GCs. */
#define TCACHE_GC_INCR \
((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1))
调用tcache_event_hard(tsd, tcache);
这个函数不区分当前正在使用哪个bin,而是通过tcache->next_gc_bin得到要处理的bin
处理完后,tcache->next_gc_bin++;
void
tcache_event_hard(tsd_t *tsd, tcache_t *tcache)
{
szind_t binind = tcache->next_gc_bin;
tcache_bin_t *tbin = &tcache->tbins[binind];
tcache_bin_info_t *tbin_info = &tcache_bin_info[binind];
if (tbin->low_water > 0) {
/*
* Flush (ceiling) 3/4 of the objects below the low water mark.
*/第一次进到这个分支的是2号bin
{tstats = {nrequests = 62}, low_water = 38, lg_fill_div = 1, ncached = 38, avail = 0x7ffff660e220}
在低水位标记冲刷四分之三的对象,
此时已分配了62次,从数组的尾部开始的,也就是从头开始的38个还是空闲的
if (binind < NBINS) {
tcache_bin_flush_small(tsd, tcache, tbin, binind,
tbin->ncached - tbin->low_water + (tbin->low_water
>> 2));
ncached - low_water + 1/4 * low_water
ncached - 3/4 * low_water = 9(一开始ncached和low_water是相等的)
只保留这么多(9个),刷掉3/4 * low_water个
} else {
tcache_bin_flush_large(tsd, tbin, binind, tbin->ncached
- tbin->low_water + (tbin->low_water >> 2), tcache);
}
/*
* Reduce fill count by 2X. Limit lg_fill_div such that the
* fill count is always at least 1.
*/
if ((tbin_info->ncached_max >> (tbin->lg_fill_div+1)) >= 1)
tbin->lg_fill_div++;
} else if (tbin->low_water < 0) {
/*
* Increase fill count by 2X. Make sure lg_fill_div stays
* greater than 0.
*/任何一个bin,在进这个函数前,low_water=-1,lg_fill_div=1
if (tbin->lg_fill_div > 1)
tbin->lg_fill_div--; 不会执行
}
tbin->low_water = tbin->ncached; 26(这里处理的是0号bin)
tcache->next_gc_bin++;轮询处理下一个bin
if (tcache->next_gc_bin == nhbins)
tcache->next_gc_bin = 0;
tcache->ev_cnt = 0; 事件重置为0
}
void
tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin,
szind_t binind, unsigned rem)
{现在缓存了ncached个,只保留rem个,冲掉ncached-rem个
arena_t *arena;
void *ptr;
unsigned i, nflush, ndeferred;
bool merged_stats = false;
assert(binind < NBINS);2
assert(rem <= tbin->ncached);9
arena = arena_choose(tsd, NULL);
assert(arena != NULL);
for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) {
/* Lock the arena bin associated with the first object. */
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(
tbin->avail[0]);
arena_t *bin_arena = extent_node_arena_get(&chunk->node);
arena_bin_t *bin = &bin_arena->bins[binind];
if (config_prof && bin_arena == arena) {
if (arena_prof_accum(arena, tcache->prof_accumbytes))
prof_idump();
tcache->prof_accumbytes = 0;
}
malloc_mutex_lock(&bin->lock);
if (config_stats && bin_arena == arena) {
assert(!merged_stats);
merged_stats = true;
bin->stats.nflushes++;
bin->stats.nrequests += tbin->tstats.nrequests;
tbin->tstats.nrequests = 0;
}
ndeferred = 0;
for (i = 0; i < nflush; i++) { 从0开始冲刷,总共要冲刷nflush个
ptr = tbin->avail[i];
assert(ptr != NULL);
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
if (extent_node_arena_get(&chunk->node) == bin_arena) {
size_t pageind = ((uintptr_t)ptr -
(uintptr_t)chunk) >> LG_PAGE;
arena_chunk_map_bits_t *bitselm =
arena_bitselm_get(chunk, pageind);
arena_dalloc_bin_junked_locked(bin_arena, chunk,
ptr, bitselm);
对这个对象进行dalloc
} else {
/*
* This object was allocated via a different
* arena bin than the one that is currently
* locked. Stash the object, so that it can be
* handled in a future pass.
*/这个对象是通过不同的area分配的,贮藏这个对象,以便在将来走到这个函数它能够被处理
tbin->avail[ndeferred] = ptr;
ndeferred++;因为是从0开始flush的,ndeferred也是从0递增的,所以ndeferred是空闲的
}
}
malloc_mutex_unlock(&bin->lock);
}
if (config_stats && !merged_stats) {
/*
* The flush loop didn't happen to flush to this thread's
* arena, so the stats didn't get merged. Manually do so now.
*/
arena_bin_t *bin = &arena->bins[binind];
malloc_mutex_lock(&bin->lock);
bin->stats.nflushes++;
bin->stats.nrequests += tbin->tstats.nrequests;
tbin->tstats.nrequests = 0;
malloc_mutex_unlock(&bin->lock);
}
memmove(tbin->avail, &tbin->avail[tbin->ncached - rem],
rem * sizeof(void *));
tbin->ncached = rem;
0-3/4的对象都冲刷的,把剩余的1/4挪到avail数组的开始
if ((int)tbin->ncached < tbin->low_water)
tbin->low_water = tbin->ncached; low_water始终不能超过ncached
}
下面研究arena_dalloc_bin_junked_locked(bin_arena, chunk, ptr, bitselm);
arena_dalloc_bin_locked_impl(arena, chunk, ptr, bitselm, true);
static void
arena_dalloc_bin_locked_impl(arena_t *arena, arena_chunk_t *chunk, void *ptr,
arena_chunk_map_bits_t *bitselm, bool junked)
{
size_t pageind, rpages_ind;
arena_run_t *run;
arena_bin_t *bin;
arena_bin_info_t *bin_info;
szind_t binind;
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; 这个地址是在33页
rpages_ind = pageind - arena_mapbits_small_runind_get(chunk, pageind);
第33页的runid是2,相对这个run的起始页的页号偏移
(gdb) p je_arena_bin_info[2]
$4 = {reg_size = 24, redzone_size = 0, reg_interval = 24, run_size = 12288, nregs = 512, bitmap_info = {nbits = 512,
nlevels = 2, levels = {{group_offset = 0}, {group_offset = 8}, {group_offset = 9}, {group_offset = 0}}},
reg0_offset = 0}
(gdb) p 12288/4096
$5 = 3
2号bin的run_size是3页
run = &arena_miscelm_get(chunk, rpages_ind)->run;通过起始页的misc得到这个run
binind = run->binind;
bin = &arena->bins[binind];
bin_info = &arena_bin_info[binind];
if (!junked && config_fill && unlikely(opt_junk_free))
arena_dalloc_junk_small(ptr, bin_info);
arena_run_reg_dalloc(run, ptr);
寄存器级别的释放
if (run->nfree == bin_info->nregs) {
arena_dissociate_bin_run(chunk, run, bin);
arena_dalloc_bin_run(arena, chunk, run, bin);
} else if (run->nfree == 1 && run != bin->runcur)
arena_bin_lower_run(arena, chunk, run, bin);
if (config_stats) {
bin->stats.ndalloc++;
bin->stats.curregs--;
}
}
JEMALLOC_INLINE_C void
arena_run_reg_dalloc(arena_run_t *run, void *ptr)
{
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
size_t mapbits = arena_mapbits_get(chunk, pageind);
szind_t binind = arena_ptr_small_binind_get(ptr, mapbits);
arena_bin_info_t *bin_info = &arena_bin_info[binind]; 上面这些都介绍过
unsigned regind = arena_run_regind(run, bin_info, ptr);
怎么通过ptr得到regind
assert(run->nfree < bin_info->nregs);
/* Freeing an interior pointer can cause assertion failure. */
assert(((uintptr_t)ptr -
((uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run)) +
(uintptr_t)bin_info->reg0_offset)) %
(uintptr_t)bin_info->reg_interval == 0);
assert((uintptr_t)ptr >=
(uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run)) +
(uintptr_t)bin_info->reg0_offset);
/* Freeing an unallocated pointer can cause assertion failure. */
assert(bitmap_get(run->bitmap, &bin_info->bitmap_info, regind));
bitmap_unset(run->bitmap, &bin_info->bitmap_info, regind);位图置1,表示空闲,和bitmap_set类似
run->nfree++; 空闲数量加1
}
JEMALLOC_INLINE unsigned
arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr)
{
unsigned shift, diff, regind;
size_t interval;
arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run);得到这个run对应的misc
void *rpages = arena_miscelm_to_rpages(miscelm);
得到这个misc对应的页的地址
/*
* Freeing a pointer lower than region zero can cause assertion
* failure.
*/
assert((uintptr_t)ptr >= (uintptr_t)rpages +
(uintptr_t)bin_info->reg0_offset);
/*
* Avoid doing division with a variable divisor if possible. Using
* actual division here can reduce allocator throughput by over 20%!
*/如果可能,尽量避免对一个变量做除法
diff = (unsigned)((uintptr_t)ptr - (uintptr_t)rpages -
bin_info->reg0_offset);计算要释放的地址和run的起始地址的距离,9576
/* Rescale (factor powers of 2 out of the numerator and denominator). */
重新调节(2的多少次方超过分子和分母)
interval = bin_info->reg_interval; 24
shift = jemalloc_ffs(interval) - 1; 0x18,最右边第一个1是第4位(从右从1开始)
3,将间隔末尾的0都去掉
diff >>= shift; 1197
interval >>= shift; 3 都缩小8倍
if (interval == 1) {如果间隔是2的某一次方
/* The divisor was a power of 2. */
regind = diff; 右移后的diff就是第几个reg
} else {
/*
* To divide by a number D that is not a power of two we
* multiply by (2^21 / D) and then right shift by 21 positions.
* D不是2的某一次方,要除D,可以先乘(2^21 / D)再右移21位
* X / D
*
* becomes
*
* (X * interval_invs[D - 3]) >> SIZE_INV_SHIFT
* X/D于是就变成了(X * interval_invs[D - 3]) >> SIZE_INV_SHIFT
X代表diff右移后的结果,D代表interval右移的结果
* We can omit the first three elements, because we never
* divide by 0, and 1 and 2 are both powers of two, which are
* handled above.
*/我们能省略开始的3个元素,因为从来不会除0,1和2又都是2的某一次方,上面已经处理过了
#define SIZE_INV_SHIFT ((sizeof(unsigned) << 3) - LG_RUN_MAXREGS)
((sizeof(4) << 3) - 9) = 23
#define SIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s)) + 1)
(((1U << 23) / (s)) + 1)
static const unsigned interval_invs[] = { 函数内申明了一个数组
SIZE_INV(3), 2^23/3 + 1
SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7),
SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11),
SIZE_INV(12), SIZE_INV(13), SIZE_INV(14), SIZE_INV(15),
SIZE_INV(16), SIZE_INV(17), SIZE_INV(18), SIZE_INV(19),
SIZE_INV(20), SIZE_INV(21), SIZE_INV(22), SIZE_INV(23),
SIZE_INV(24), SIZE_INV(25), SIZE_INV(26), SIZE_INV(27),
SIZE_INV(28), SIZE_INV(29), SIZE_INV(30), SIZE_INV(31)
};
if (likely(interval <= ((sizeof(interval_invs) /
sizeof(unsigned)) + 2))) {
regind = (diff * interval_invs[interval - 3]) >>
SIZE_INV_SHIFT;乘以某个数再右移
} else
regind = diff / interval;
#undef SIZE_INV
#undef SIZE_INV_SHIFT
}
assert(diff == regind * interval);
assert(regind < bin_info->nregs);
return (regind);
}
里面tcache->ev_cnt++;
当tcache->ev_cnt == TCACHE_GC_INCR(211)时
/*
* TCACHE_GC_SWEEP is the approximate number of allocation events between
* full GC sweeps. Integer rounding may cause the actual number to be
* slightly higher, since GC is performed incrementally.
*/
#define TCACHE_GC_SWEEP 8192
/* Number of tcache allocation/deallocation events between incremental GCs. */
#define TCACHE_GC_INCR \
((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1))
调用tcache_event_hard(tsd, tcache);
这个函数不区分当前正在使用哪个bin,而是通过tcache->next_gc_bin得到要处理的bin
处理完后,tcache->next_gc_bin++;
void
tcache_event_hard(tsd_t *tsd, tcache_t *tcache)
{
szind_t binind = tcache->next_gc_bin;
tcache_bin_t *tbin = &tcache->tbins[binind];
tcache_bin_info_t *tbin_info = &tcache_bin_info[binind];
if (tbin->low_water > 0) {
/*
* Flush (ceiling) 3/4 of the objects below the low water mark.
*/第一次进到这个分支的是2号bin
{tstats = {nrequests = 62}, low_water = 38, lg_fill_div = 1, ncached = 38, avail = 0x7ffff660e220}
在低水位标记冲刷四分之三的对象,
此时已分配了62次,从数组的尾部开始的,也就是从头开始的38个还是空闲的
if (binind < NBINS) {
tcache_bin_flush_small(tsd, tcache, tbin, binind,
tbin->ncached - tbin->low_water + (tbin->low_water
>> 2));
ncached - low_water + 1/4 * low_water
ncached - 3/4 * low_water = 9(一开始ncached和low_water是相等的)
只保留这么多(9个),刷掉3/4 * low_water个
} else {
tcache_bin_flush_large(tsd, tbin, binind, tbin->ncached
- tbin->low_water + (tbin->low_water >> 2), tcache);
}
/*
* Reduce fill count by 2X. Limit lg_fill_div such that the
* fill count is always at least 1.
*/
if ((tbin_info->ncached_max >> (tbin->lg_fill_div+1)) >= 1)
tbin->lg_fill_div++;
} else if (tbin->low_water < 0) {
/*
* Increase fill count by 2X. Make sure lg_fill_div stays
* greater than 0.
*/任何一个bin,在进这个函数前,low_water=-1,lg_fill_div=1
if (tbin->lg_fill_div > 1)
tbin->lg_fill_div--; 不会执行
}
tbin->low_water = tbin->ncached; 26(这里处理的是0号bin)
tcache->next_gc_bin++;轮询处理下一个bin
if (tcache->next_gc_bin == nhbins)
tcache->next_gc_bin = 0;
tcache->ev_cnt = 0; 事件重置为0
}
void
tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin,
szind_t binind, unsigned rem)
{现在缓存了ncached个,只保留rem个,冲掉ncached-rem个
arena_t *arena;
void *ptr;
unsigned i, nflush, ndeferred;
bool merged_stats = false;
assert(binind < NBINS);2
assert(rem <= tbin->ncached);9
arena = arena_choose(tsd, NULL);
assert(arena != NULL);
for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) {
/* Lock the arena bin associated with the first object. */
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(
tbin->avail[0]);
arena_t *bin_arena = extent_node_arena_get(&chunk->node);
arena_bin_t *bin = &bin_arena->bins[binind];
if (config_prof && bin_arena == arena) {
if (arena_prof_accum(arena, tcache->prof_accumbytes))
prof_idump();
tcache->prof_accumbytes = 0;
}
malloc_mutex_lock(&bin->lock);
if (config_stats && bin_arena == arena) {
assert(!merged_stats);
merged_stats = true;
bin->stats.nflushes++;
bin->stats.nrequests += tbin->tstats.nrequests;
tbin->tstats.nrequests = 0;
}
ndeferred = 0;
for (i = 0; i < nflush; i++) { 从0开始冲刷,总共要冲刷nflush个
ptr = tbin->avail[i];
assert(ptr != NULL);
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
if (extent_node_arena_get(&chunk->node) == bin_arena) {
size_t pageind = ((uintptr_t)ptr -
(uintptr_t)chunk) >> LG_PAGE;
arena_chunk_map_bits_t *bitselm =
arena_bitselm_get(chunk, pageind);
arena_dalloc_bin_junked_locked(bin_arena, chunk,
ptr, bitselm);
对这个对象进行dalloc
} else {
/*
* This object was allocated via a different
* arena bin than the one that is currently
* locked. Stash the object, so that it can be
* handled in a future pass.
*/这个对象是通过不同的area分配的,贮藏这个对象,以便在将来走到这个函数它能够被处理
tbin->avail[ndeferred] = ptr;
ndeferred++;因为是从0开始flush的,ndeferred也是从0递增的,所以ndeferred是空闲的
}
}
malloc_mutex_unlock(&bin->lock);
}
if (config_stats && !merged_stats) {
/*
* The flush loop didn't happen to flush to this thread's
* arena, so the stats didn't get merged. Manually do so now.
*/
arena_bin_t *bin = &arena->bins[binind];
malloc_mutex_lock(&bin->lock);
bin->stats.nflushes++;
bin->stats.nrequests += tbin->tstats.nrequests;
tbin->tstats.nrequests = 0;
malloc_mutex_unlock(&bin->lock);
}
memmove(tbin->avail, &tbin->avail[tbin->ncached - rem],
rem * sizeof(void *));
tbin->ncached = rem;
0-3/4的对象都冲刷的,把剩余的1/4挪到avail数组的开始
if ((int)tbin->ncached < tbin->low_water)
tbin->low_water = tbin->ncached; low_water始终不能超过ncached
}
下面研究arena_dalloc_bin_junked_locked(bin_arena, chunk, ptr, bitselm);
arena_dalloc_bin_locked_impl(arena, chunk, ptr, bitselm, true);
static void
arena_dalloc_bin_locked_impl(arena_t *arena, arena_chunk_t *chunk, void *ptr,
arena_chunk_map_bits_t *bitselm, bool junked)
{
size_t pageind, rpages_ind;
arena_run_t *run;
arena_bin_t *bin;
arena_bin_info_t *bin_info;
szind_t binind;
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; 这个地址是在33页
rpages_ind = pageind - arena_mapbits_small_runind_get(chunk, pageind);
第33页的runid是2,相对这个run的起始页的页号偏移
(gdb) p je_arena_bin_info[2]
$4 = {reg_size = 24, redzone_size = 0, reg_interval = 24, run_size = 12288, nregs = 512, bitmap_info = {nbits = 512,
nlevels = 2, levels = {{group_offset = 0}, {group_offset = 8}, {group_offset = 9}, {group_offset = 0}}},
reg0_offset = 0}
(gdb) p 12288/4096
$5 = 3
2号bin的run_size是3页
run = &arena_miscelm_get(chunk, rpages_ind)->run;通过起始页的misc得到这个run
binind = run->binind;
bin = &arena->bins[binind];
bin_info = &arena_bin_info[binind];
if (!junked && config_fill && unlikely(opt_junk_free))
arena_dalloc_junk_small(ptr, bin_info);
arena_run_reg_dalloc(run, ptr);
寄存器级别的释放
if (run->nfree == bin_info->nregs) {
arena_dissociate_bin_run(chunk, run, bin);
arena_dalloc_bin_run(arena, chunk, run, bin);
} else if (run->nfree == 1 && run != bin->runcur)
arena_bin_lower_run(arena, chunk, run, bin);
if (config_stats) {
bin->stats.ndalloc++;
bin->stats.curregs--;
}
}
JEMALLOC_INLINE_C void
arena_run_reg_dalloc(arena_run_t *run, void *ptr)
{
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
size_t mapbits = arena_mapbits_get(chunk, pageind);
szind_t binind = arena_ptr_small_binind_get(ptr, mapbits);
arena_bin_info_t *bin_info = &arena_bin_info[binind]; 上面这些都介绍过
unsigned regind = arena_run_regind(run, bin_info, ptr);
怎么通过ptr得到regind
assert(run->nfree < bin_info->nregs);
/* Freeing an interior pointer can cause assertion failure. */
assert(((uintptr_t)ptr -
((uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run)) +
(uintptr_t)bin_info->reg0_offset)) %
(uintptr_t)bin_info->reg_interval == 0);
assert((uintptr_t)ptr >=
(uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run)) +
(uintptr_t)bin_info->reg0_offset);
/* Freeing an unallocated pointer can cause assertion failure. */
assert(bitmap_get(run->bitmap, &bin_info->bitmap_info, regind));
bitmap_unset(run->bitmap, &bin_info->bitmap_info, regind);位图置1,表示空闲,和bitmap_set类似
run->nfree++; 空闲数量加1
}
JEMALLOC_INLINE unsigned
arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr)
{
unsigned shift, diff, regind;
size_t interval;
arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run);得到这个run对应的misc
void *rpages = arena_miscelm_to_rpages(miscelm);
得到这个misc对应的页的地址
/*
* Freeing a pointer lower than region zero can cause assertion
* failure.
*/
assert((uintptr_t)ptr >= (uintptr_t)rpages +
(uintptr_t)bin_info->reg0_offset);
/*
* Avoid doing division with a variable divisor if possible. Using
* actual division here can reduce allocator throughput by over 20%!
*/如果可能,尽量避免对一个变量做除法
diff = (unsigned)((uintptr_t)ptr - (uintptr_t)rpages -
bin_info->reg0_offset);计算要释放的地址和run的起始地址的距离,9576
/* Rescale (factor powers of 2 out of the numerator and denominator). */
重新调节(2的多少次方超过分子和分母)
interval = bin_info->reg_interval; 24
shift = jemalloc_ffs(interval) - 1; 0x18,最右边第一个1是第4位(从右从1开始)
3,将间隔末尾的0都去掉
diff >>= shift; 1197
interval >>= shift; 3 都缩小8倍
if (interval == 1) {如果间隔是2的某一次方
/* The divisor was a power of 2. */
regind = diff; 右移后的diff就是第几个reg
} else {
/*
* To divide by a number D that is not a power of two we
* multiply by (2^21 / D) and then right shift by 21 positions.
* D不是2的某一次方,要除D,可以先乘(2^21 / D)再右移21位
* X / D
*
* becomes
*
* (X * interval_invs[D - 3]) >> SIZE_INV_SHIFT
* X/D于是就变成了(X * interval_invs[D - 3]) >> SIZE_INV_SHIFT
X代表diff右移后的结果,D代表interval右移的结果
* We can omit the first three elements, because we never
* divide by 0, and 1 and 2 are both powers of two, which are
* handled above.
*/我们能省略开始的3个元素,因为从来不会除0,1和2又都是2的某一次方,上面已经处理过了
#define SIZE_INV_SHIFT ((sizeof(unsigned) << 3) - LG_RUN_MAXREGS)
((sizeof(4) << 3) - 9) = 23
#define SIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s)) + 1)
(((1U << 23) / (s)) + 1)
static const unsigned interval_invs[] = { 函数内申明了一个数组
SIZE_INV(3), 2^23/3 + 1
SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7),
SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11),
SIZE_INV(12), SIZE_INV(13), SIZE_INV(14), SIZE_INV(15),
SIZE_INV(16), SIZE_INV(17), SIZE_INV(18), SIZE_INV(19),
SIZE_INV(20), SIZE_INV(21), SIZE_INV(22), SIZE_INV(23),
SIZE_INV(24), SIZE_INV(25), SIZE_INV(26), SIZE_INV(27),
SIZE_INV(28), SIZE_INV(29), SIZE_INV(30), SIZE_INV(31)
};
if (likely(interval <= ((sizeof(interval_invs) /
sizeof(unsigned)) + 2))) {
regind = (diff * interval_invs[interval - 3]) >>
SIZE_INV_SHIFT;乘以某个数再右移
} else
regind = diff / interval;
#undef SIZE_INV
#undef SIZE_INV_SHIFT
}
assert(diff == regind * interval);
assert(regind < bin_info->nregs);
return (regind);
}
阅读全文
0 0
- jemalloc横向分析(六)tcache_event事件执行
- jemalloc横向分析(二) rtree分析
- jemalloc横向分析(一) 核心结构体
- jemalloc横向分析(五)tcache分配内存
- jemalloc横向分析(三) arena_run_split_large使用分配的chunk存放tcache
- jemalloc横向分析(四) tcache分配内存中使用到的位图bitmap
- jemalloc源码解读(六)基数树
- jemalloc原理分析
- netty(二):事件执行分析
- jemalloc
- jemalloc
- jemalloc
- hive原理与源码分析-物理执行计划与执行引擎(六)
- (六)事件
- 横向ListView(六) —— 将自定义的横向ListView改成竖向
- (六)Git 执行更改
- Mybatis执行CachingExecutor(六)
- Android onTouch 点击事件执行两次分析
- iOS 字典和数组写入plist文件存到应用沙盒当中(含读取)
- Spring 框架的设计理念与设计模式分析
- ubuntu下安装thrift
- python进行机器学习中的SVM
- java Class与静态初始化
- jemalloc横向分析(六)tcache_event事件执行
- CodeForces
- 设计模式之单例模式
- [P2657]低头一族
- Centos7.0 安装ELK(5.5.1版本)
- 老用户快速从经典网络迁移VPC,阿里云提供便捷解决方案
- Party Games UVA
- 学习RxJava
- 监听div内容的变化