5.7.2.5 malloc_consolidate()
malloc_consolidate() 函数用于将 fast bins 中的 chunk 合并,并加入 unsorted bin 中,其实现源代码如下:
/* ------------------------- malloc_consolidate ------------------------- malloc_consolidate is a specialized version of free() that tears down chunks held in fastbins. Free itself cannot be used for this purpose since, among other things, it might place chunks back onto fastbins. So, instead, we need to use a minor variant of the same code. Also, because this routine needs to be called the first time through malloc anyway, it turns out to be the perfect place to trigger initialization code. */ #if __STD_C static void malloc_consolidate(mstate av) #else static void malloc_consolidate(av) mstate av; #endif { mfastbinptr* fb; /* current fastbin being consolidated */ mfastbinptr* maxfb; /* last fastbin (for loop control) */ mchunkptr p; /* current chunk being consolidated */ mchunkptr nextp; /* next chunk to consolidate */ mchunkptr unsorted_bin; /* bin header */ mchunkptr first_unsorted; /* chunk to link to */ /* These have same use as in free() */ mchunkptr nextchunk; INTERNAL_SIZE_T size; INTERNAL_SIZE_T nextsize; INTERNAL_SIZE_T prevsize; int nextinuse; mchunkptr bck; mchunkptr fwd; /* If max_fast is 0, we know that av hasn't yet been initialized, in which case do so below */ if (get_max_fast () != 0) { clear_fastchunks(av); unsorted_bin = unsorted_chunks(av);
如果全局变量 global_max_fast 不为零,表示 ptmalloc 已经初始化,清除分配区 flag 中 fast bin 的标志位,该标志位表示分配区的 fast bins 中包含空闲 chunk 。然后获得分配区的 unsorted bin 。
/* Remove each chunk from fast bin and consolidate it, placing it then in unsorted bin. Among other reasons for doing this, placing in unsorted bin avoids needing to calculate actual bins until malloc is sure that chunks aren't immediately going to be reused anyway. */ #if 0 /* It is wrong to limit the fast bins to search using get_max_fast because, except for the main arena, all the others might have blocks in the high fast bins. It's not worth it anyway, just search all bins all the time. */ maxfb = &fastbin (av, fastbin_index(get_max_fast ())); #else maxfb = &fastbin (av, NFASTBINS - 1); #endif fb = &fastbin (av, 0); 将分配区最大的一个fast bin赋值给maxfb,第一个fast bin赋值给fb,然后遍历fast bins。 do { #ifdef ATOMIC_FASTBINS p = atomic_exchange_acq (fb, 0); #else p = *fb; #endif if (p != 0) { #ifndef ATOMIC_FASTBINS *fb = 0; #endif 获取当前遍历的fast bin中空闲chunk单向链表的头指针赋值给p,如果p不为0,将当前fast bin链表的头指针赋值为0,即删除了该fast bin中的空闲chunk链表。 do { check_inuse_chunk(av, p); nextp = p->fd; 将空闲chunk链表的下一个chunk赋值给nextp。 /* Slightly streamlined version of consolidation code in free() */ size = p->size & ~(PREV_INUSE|NON_MAIN_ARENA); nextchunk = chunk_at_offset(p, size); nextsize = chunksize(nextchunk); 获得当前chunk的size,需要去除size中的PREV_INUSE和NON_MAIN_ARENA标志,并获取相邻的下一个chunk和下一个chunk的大小。 if (!prev_inuse(p)) { prevsize = p->prev_size; size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); unlink(p, bck, fwd); } 如果当前chunk的前一个chunk空闲,则将当前chunk与前一个chunk合并成一个空闲chunk,由于前一个chunk空闲,则当前chunk的prev_size保存了前一个chunk的大小,计算出合并后的chunk大小,并获取前一个chunk的指针,将前一个chunk从空闲链表中删除。 if (nextchunk != av->top) { nextinuse = inuse_bit_at_offset(nextchunk, nextsize); 如果与当前chunk相邻的下一个chunk不是分配区的top chunk,查看与当前chunk相邻的下一个chunk是否处于inuse状态。 if (!nextinuse) { size += nextsize; unlink(nextchunk, bck, fwd); } else clear_inuse_bit_at_offset(nextchunk, 0); 如果与当前chunk相邻的下一个chunk处于inuse状态,清除当前chunk的inuse状态,则当前chunk空闲了。否则,将相邻的下一个空闲chunk从空闲链表中删除,并计算当前chunk与下一个chunk合并后的chunk大小。 first_unsorted = unsorted_bin->fd; unsorted_bin->fd = p; first_unsorted->bk = p; 将合并后的chunk加入unsorted bin的双向循环链表中。 if (!in_smallbin_range (size)) { p->fd_nextsize = NULL; p->bk_nextsize = NULL; } 如果合并后的chunk属于large bin,将chunk的fd_nextsize和bk_nextsize设置为NULL,因为在unsorted bin中这两个字段无用。 set_head(p, size | PREV_INUSE); p->bk = unsorted_bin; p->fd = first_unsorted; set_foot(p, size); 设置合并后的空闲chunk大小,并标识前一个chunk处于inuse状态,因为必须保证不能有两个相邻的chunk都处于空闲状态。然后将合并后的chunk加入unsorted bin的双向循环链表中。最后设置合并后的空闲chunk的foot,chunk空闲时必须设置foot,该foot处于下一个chunk的prev_size中,只有chunk空闲是foot才是有效的。 } else { size += nextsize; set_head(p, size | PREV_INUSE); av->top = p; } 如果当前chunk的下一个chunk为top chunk,则将当前chunk合并入top chunk,修改top chunk的大小。 } while ( (p = nextp) != 0); 直到遍历完当前fast bin中的所有空闲chunk。 } } while (fb++ != maxfb); 直到遍历完所有的fast bins。 } else { malloc_init_state(av); check_malloc_state(av); 如果ptmalloc没有初始化,初始化ptmalloc。 } }