Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1401561
  • 博文数量: 343
  • 博客积分: 13098
  • 博客等级: 上将
  • 技术积分: 2862
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-06 00:35
文章存档

2012年(131)

2011年(31)

2010年(53)

2009年(23)

2008年(62)

2007年(2)

2006年(36)

2005年(5)

分类: LINUX

2008-06-01 20:47:09

dlmalloc源码剖析之:sYSMALLOc
版权声明: 本文章由vt.buxiu发布在,版权归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);
}

阅读(1295) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~