内存分配器三

已经实现了自己的malloc函数Imalloc,但是内存管理还是需要calloc,free,relloc函数来管理内存:
calloc:在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针,并将内存空间置0,在32位机上是4bytes一个内存块大小;如果分配不成功,返回NULL。

 void *Icalloc(size_t number,size_t size){
    size_t *new;
    size_t s4,i;
    new=Imalloc(number*size);
    if(new){
        s4=align4(number*size)<<2;
        for(i=0;i<s4;i++)
            new[i]=0;
    }
    return (new);
} 

在free的时候有两个问题需要解决:验证需要被free的块,避免内存碎片。
验证需要被free块需要做两件事:是否在之前malloc所分配的区域内;该地址确实是通过malloc分配的。问题一比较地址就可以了。问题二有两个方法:在meta-data中添加magic number,free的时候检查该值;添加一个magic pointer,指向数据区的第一个字节。采用方法二。在避免碎片的时候需要合并小的内存块,需要将该内存块的前后合并起来,但是单向链表难以操作,所以讲meta-data改为双向链表。由于数据结构改变,相应的需要修改之前的函数。

typedef struct s_block *p_block;

struct s_block{
    size_t size;
    p_block next;
    p_block prev;
    int free;
    void *ptr;
    char data[1];
};

验证地址合法性:

p_block get_block(void *p){
    char *temp;
    temp=p;
    return(p=temp-=META_DATA_SIZE);
}

int valid_addr(void *p){
    if(base){
        if(p>base&&p<sbrk(0))
            return (p==(get_block(p)->ptr));
    }
    return (0);
}

合并内存块:

p_block fusion(p_block b){
    if(b->next&&b->next->free){
        b->size+=META_DATA_SIZE+b->next->size;
        b->next=b->next->next;  
        if(b->next)
            b->next->prev=b;
    }
    return (b);
}

free函数:
验证指针通过:
1. 获取内存块的地址
2. 标记free为1
3. 如果存在之前的块并且为free为1,合并这两块内存
4. 同样处理最后一块
5. 如果是最后一块内存块
6. 如果没有内存块,返回最初状态(base 置为NULL)
如果验证不通过就什么也不处理。
int brk(const void *addr)将break设置到addr处

void Ifree(void *p){
    p_block b;
    if(valid_addr(p)){
        b=get_block(p);
        b->free=1;
        if(b->prev&&b->prev->free)
            b=fusion(b->prev);
        if(b->next)
            fusion(b);
        else{
            if(b->prev)
                b->prev->next=NULL;
            else
                base=NULL;
            brk(b);
        }
    }
}

realloc 函数:释放老的动态内存块,按照给出的尺寸分配新的动态内存块,老的内存块的内容尽量复制到新的内存块

复制内存:

void copy_block(p_block src,p_block dst){
    int *sdata,*ddata;
    size_t i;
    sdata=src->ptr;
    ddata=dst->ptr;
    for(i=0;i*4<src->size&&i*4<dst->size;i++)
        ddata[i]=sdata[i];
}

重写realloc:
1. 使用Imalloc分配新的内存块
2. 从旧的内存块复制内容到新的内存块
3. 释放老的内存块
4. 返回新的指针
如果:
1. size没变,或者额外size足够,则不操作
2. 如果缩小,可以split
3. 如果next是free然后提供了足够的空间大小,可以合并在split

void *Irealloc(void *p,size_t size){
    size_t s;
    p_block b,new;
    void *newp;
    if(!p)
        return (Imalloc(size));
    if(valid_addr(p)){
        s=align4(size);
        b=get_block(p);
        if(b->size>=s){
            if(b->size-s>=(META_DATA_SIZE+4))
                split_block(b,s);
        }else{
            if(b->next&&b->next->free&&
              (b->size+META_DATA_SIZE+b->next->size)>=s){
                fusion(b);
                if(b->size-s>=(META_DATA_SIZE+4))
                split_block(b,s);
            }else{
                newp=Imalloc(s);
                if(!newp)
                    return (NULL);
                new=get_block(newp);
                copy_block(b,new);
                    Ifree(p);
                return(newp);
            }
        }
        return (p);
    }
    return (NULL);
}

至此,已基本完成了malloc,free,realloc,calloc的功能,但也只是简单粗略的实现,但也还有很多地方值得修改的,比如文章http://blog.jobbole.com/75656/描述的那样:
1. 分配内存较大块内存时,使用mmap替代sbrk
2. 维护多个链表,提高查找效率
也有后面需要做的就是http://www.skywind.me/blog/archives/1480中提到的一些功能和观点:
1. 做好标记和保护,避免二次释放
2. 修改查找算法,查找最合适大小的内存块上
3. 伙伴算法
4. freelist
5. slab代替Freelist
6. 混合分配策略
7. 实现地址着色
8. 优化缓存竞争

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值