debug musl( 六 )


这里分两种情况:
如果之后如果还是没有空闲的说明此时 brk 以及不能连续扩展内存,因此需要通过 mmap 申请内存作为空闲的。mmap 的内存大小通过计算,并且每次 mmap 之后,下次 mmap 的内存数量翻倍 。和 brk 一样,获得的内存中的第一块内存页不能使用,由于 mmap 的内存没有读写权限,因此需要将 ctx. 指向的内存页赋上可读写权限 。
if (!ctx.avail_meta_area_count) {size_t n = 2UL << ctx.meta_alloc_shift;p = mmap(0, n * pagesize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);if (p == MAP_FAILED) return 0;ctx.avail_meta_areas = p + pagesize;ctx.avail_meta_area_count = (n - 1) * (pagesize >> 12);ctx.meta_alloc_shift++;}p = ctx.avail_meta_areas;if ((uintptr_t) p & (pagesize - 1)) need_unprotect = 0;if (need_unprotect)if (mprotect(p, pagesize, PROT_READ | PROT_WRITE) && errno != ENOSYS)return 0;
最后就是从空闲的中获取一个然后再从该中获取空闲的 meta。
ctx.avail_meta_area_count--;ctx.avail_meta_areas = p + 4096;if (ctx.meta_area_tail) {ctx.meta_area_tail->next = (void *) p;} else {ctx.meta_area_head = (void *) p;}ctx.meta_area_tail = (void *) p;ctx.meta_area_tail->check = ctx.secret;ctx.avail_meta_count = ctx.meta_area_tail->nslots = (4096 - sizeof(struct meta_area)) / sizeof *m;ctx.avail_meta = ctx.meta_area_tail->slots;
现在已经可以确定和 meta 的在内存中的关系如下图所示(以 mmap 扩展为例) 。
group
struct group {struct meta *meta;unsigned char active_idx : 5;char pad[UNIT - sizeof(struct meta *) - 1];unsigned char storage[];};
group中即保存有需要分配出去的chunk 。
meta *meta:所属的meta的地址
char :5:5个比特,表示还有多少可用chunk
char pad[UNIT - ( meta *) - 1]:手动16字节对齐
char []:要分配出去的内存空间,chunk
首先获取一个 meta ,然后根据经验以及当前内存状态计算出需要申请的 group 中 chunk 的数量 。
size_t size = UNIT * size_classes[sc];int i = 0, cnt;unsigned char *p;struct meta *m = alloc_meta();if (!m) return 0;size_t usage = ctx.usage_by_class[sc];size_t pagesize = PGSZ;int active_idx;if (sc < 9) {while (i < 2 && 4 * small_cnt_tab[sc][i] > usage)i++;cnt = small_cnt_tab[sc][i];} else {// lookup max number of slots fitting in power-of-two size// from a table, along with number of factors of two we// can divide out without a remainder or reaching 1.cnt = med_cnt_tab[sc & 3];// reduce cnt to avoid excessive eagar allocation.while (!(cnt & 1) && 4 * cnt > usage)cnt >>= 1;// data structures don't support groups whose slot offsets// in units don't fit in 16 bits.while (size * cnt >= 65536 * UNIT)cnt >>= 1;}// If we selected a count of 1 above but it's not sufficient to use// mmap, increase to 2. Then it might be; if not it will nest.if (cnt == 1 && size * cnt + UNIT <= pagesize / 2) cnt = 2;
之后分两种情况 。
如果所需内存大于页大小的一半则采用 mmap 的方式获取内存,期间也会对 group 中 chunk 的数量进行调整 。注意的初值为max ? ( 0 , min ? ( ?? 16 size ? ? 1 , cnt ? 1 ) ) \max(0,\min(\left \ \frac{\text{}-16}{\text{size}} \right \-1 ,\text{cnt}-1)) max(0,min(??16???1,cnt?1))。
// All choices of size*cnt are "just below" a power of two, so anything// larger than half the page size should be allocated as whole pages.if (size * cnt + UNIT > pagesize / 2) {// check/update bounce counter to start/increase retention// of freed maps, and inhibit use of low-count, odd-size// small mappings and single-slot groups if activated.int nosmall = is_bouncing(sc);account_bounce(sc);step_seq();// since the following count reduction opportunities have// an absolute memory usage cost, don't overdo them. count// coarse usage as part of usage.if (!(sc & 1) && sc