// 当malloc无法满足nb bytes大小请求时,调用sysmalloc向OS获取更多内存,因此av->top将被扩展
static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av) { #if HAVE_MMAP //如果定义此宏,默认是定义了的,doug lea为windows也实现了一个模拟版本
//如果请求的大小nb达到了mmap分配阀值,并且通过mmap申请的内存块个数没有达到参数设置的上限
if ((unsigned long)(nb) >= (unsigned long)(av->mmap_threshold) &&(av->n_mmaps < av->n_mmaps_max)) { //调整分配大小,多分配8+4个字节,并按pagesize对齐
size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask; //调用mmap获得内存
mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); if(mm){//如果mmap分配成功
return chunk2mem(p);//将mmap获得内存返回给应用
} //mmap如果失败,继续向下
} #endif /*没有mmap可用,或mmap不成功,或size每到达mapp阀值,则需要调整top*/ //将原来由top内存块信息记录下来
old_top = av->top; old_size = chunksize(old_top); old_end = (char*)(chunk_at_offset(old_top, old_size)); //调整请求的size
size = nb + av->top_pad + MINSIZ; /*如果空间连续,先减去已经存在的top空间,再向操作系统申请*/ if (contiguous(av)) size -= old_size; //调用sbrk向OS要求扩展heap空间
brk = (char*)(MORECORE(size)); //如果有mmap继续尝试通过mmap分配空间
#if HAVE_MMAP if (brk == (char*)(MORECORE_FAILURE)) { //不能和原来的brk分配空间连续了,单独分配,把之前的size修正
if (contiguous(av)) size = (size + old_size + pagemask) & ~pagemask; //调用mmap申请空间
brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); //mmap申请成功
if (brk != (char*)(MORECORE_FAILURE)) { snd_brk = brk + size;//记录申请得到的内存块尾部地址
//因为通过mmap扩展空间了,记录标记为top不再是连续的了
set_noncontiguous(av); } } #endif //如果是通过brk扩展内存成功的,则扩展top空间
if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) { set_head(old_top, (size + old_size) | PREV_INUSE); } else//否则,即通过mmap(brk备份)分配成功的内存;或调用malloc之间有其他人调用了brk
{//这时候需要调整top相关信息
front_misalign = 0; end_misalign = 0; correction = 0; aligned_brk = brk; if (contiguous(av)) { //调用malloc之间有其他人调用了brk
//brk内存头部按8bytes对齐
front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK; //将原来top剩余的size,算到新的brk扩展的空间内,多申请这么大
correction += old_size; //brk内存尾部按pagesize对齐
end_misalign = (INTERNAL_SIZE_T)(brk + size + correction); //计算因为头部对齐,和尾部对齐需要的额外空间大小
correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign; //多向操作系统申请因为对齐需要的内存
snd_brk = (char*)(MORECORE(correction)); } else{ //mmap分配的内存
//通过mmap扩展的内存,snd_brk指向mmap内存快的尾部
//通过mmap分配的不连续,在mmap请求前就已经按页对齐,所以这里不需要再调整对齐了
if (snd_brk == (char*)(MORECORE_FAILURE)) { snd_brk = (char*)(MORECORE(0)); } } //av->top指向新扩展的头部,设置top->size
//av->top可能是原有top的扩展(连续)(这种情况不进这个分支)
//也可能是原来的top->size移过去,新的一块brk空间,与原来的不连续
//还有可能是来自一块mmap的空间头部
av->top = (mchunkptr)aligned_brk; set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); av->sbrked_mem += correction; /*如果不是第一次调用sysmalloc,程序走到这里说明通过mmap扩展,或中间有插入的brk 因此需要在原来的top后面插入边界,放上上面的top中合并操作合并了非自己管理的内存*/ if (old_size != 0) {//!=0说明不是第一次执行到这里
//插入边界标志块
chunk_at_offset(old_top, old_size)->size = SIZE_SZ|PREV_INUSE; //插入边界标志块
chunk_at_offset(old_top, old_size + SIZE_SZ)->size = SIZE_SZ|PREV_INUSE; //如果老的top空间还比较大,将其释放
if (old_size >= MINSIZE) { fREe(chunk2mem(old_top)); } } } p = av->top; size = chunksize(p); //从top分配一块nb大小的内存快满足应用需要
remainder_size = size - nb; remainder = chunk_at_offset(p, nb); av->top = remainder; set_head(p, nb | PREV_INUSE);//最顶部着一块的p-bit肯定要设为inuse
set_head(remainder, remainder_size | PREV_INUSE); return chunk2mem(p); }
|