Chinaunix首页 | 论坛 | 博客
  • 博客访问: 192601
  • 博文数量: 73
  • 博客积分: 5000
  • 博客等级: 大校
  • 技术积分: 1160
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-23 15:53
文章分类

全部博文(73)

文章存档

2011年(1)

2009年(72)

我的朋友

分类: LINUX

2009-04-23 16:46:32

dlmalloc源码剖析之:sYSMALLOc

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

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

// malloc无法满足nb bytes大小请求时,调用sysmallocOS获取更多内存,因此av->top将被扩展
static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av)
...{

#if HAVE_MMAP   //如果定义此宏,默认是定义了的,doug leawindows也实现了一个模拟版本
    
//如果请求的大小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;
    
    
//调用sbrkOS要求扩展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);
}


 

作者:

 

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