doug lea malloc源码剖析之:sYSMALLOc

Posted ouyangbuxiu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了doug lea malloc源码剖析之:sYSMALLOc相关的知识,希望对你有一定的参考价值。

 

dlmalloc源码剖析之:sYSMALLOc

版权声明: 本文章由vt.buxiu发布在 www.vtzone.org,版权归vtzone研究小组所有,转载请保持此声明!!!

@@内容摘要:
       sYSMALLOc函数用于合并fastbin中的空闲内存块,是doug lea malloc(dlmalloc)重要的函数之一。本文以dlmalloc2.7.0版本为基础,先以伪代码的形式介绍sYSMALLOc函数的主要流程。@@
//  当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);
}



 

作者:vt.buxiu@www.vtzone.org

 

 

以上是关于doug lea malloc源码剖析之:sYSMALLOc的主要内容,如果未能解决你的问题,请参考以下文章

doug lea malloc源码剖析之:malloc_consolidate

doug lea malloc源码剖析之:sYSMALLOc

doug lea malloc源码剖析之:sYSMALLOc

doug lea malloc源码剖析之:sYSMALLOc

doug lea malloc源码剖析之:sYSMALLOc

dlmalloc源码剖析之:mALLOc