內存分配器二

雖然在IMalloc.c實現了內存申請的工作,但是這比實際中malloc函數的功能差了很多。必須要將堆中申請的內存管理起來,才能更好地實現malloc函數以及後面的free和realloc函數。
本節內容主要介紹完整實現malloc的功能,可以用於內存塊管理。
需要給每個內存塊添加額外的信息(meta-data):內存塊的大小,下一個內存塊的地址,當前內存塊是否可用。meta-data應該在malloc分配的內存塊之前。C語言描述該數據結構如下

typedef struct s_block *p_block;
struct s_block
{
    size_t size;
    p_block next;
    int free;
    char data[1];//內存塊的第一個字節,長度沒有算在meta-data中,數組真是神奇的指針
}; 

在內存中struct是一塊連續的字段,在32位系統中,size_t爲4bytes,所以總共meta-data佔12bytes。
#define META_DATA_SIZE 12
尋找合適的block採用First fit策略:從頭開始,使用第一個足夠滿足分配空間的內存塊。另外一種方式是Best策略:從頭開始,遍歷所有塊,使用數據區大小大於size且差值最小的塊作爲此次分配塊。

在內存需要將分配的內存對齊,32位系統中需要4字節對齊,使用宏來使大小對齊4,位4的倍數
#define align4(x) (((((x)-1)>>2)<<2)+4)
first fit查找合適內存塊:

void *base=NULL;
p_block find_block(p_block *last,size_t size){
    p_block b=base;
    while(b&&!(b->free&&b->size>=size)){
        *last=b;
        b=b->next;
    }   
    return (b);
}

內存塊不足時,擴展內存塊:

    p_block extend_heap(p_block last,size_t s){
    p_block b;
    b=sbrk(0);
    s=align4(s);
    if(sbrk(META_DATA_SIZE+s)==(void*)-1)
        return (NULL);
    b->size=s;
    b->next=NULL;
    if(last)
        last->next=b;
    b->free=0;
    return (b);
}

分裂內存塊,防止內存浪費:

    p_block extend_heap(p_block last,size_t s){
    p_block b;
    b=sbrk(0);
    s=align4(s);
    if(sbrk(META_DATA_SIZE+s)==(void*)-1)
        return (NULL);
    b->size=s;
    b->next=NULL;
    if(last)
        last->next=b;
    b->free=0;
    return (b);
}

重寫IMalloc函數

void *Imalloc(size_t size){
    p_block b,last;
    size_t s;
    s=align4(size);
    if(base){
        last=base;
        b=find_block(&last,s);
        if(b){
            //可以分裂內存塊
            if((b->size-s)>=META_DATA_SIZE+4)
                split_block(b,s);
                b->free=0;
        }else{
            //沒有找到合適的內存塊
            b=extend_heap(last,s);
            if(!b)
                return (NULL)   ;
        }
    }else{
        //第一次申請
        b=extend_heap(NULL,s);
        if(!b)
            return (NULL)   ;
        base=b;
    }
    return (b->data);
}

gdb調試查看
int *p=(int*)Imalloc(sizeof(int)*2);
int *pp=(int*)Imalloc(sizeof(int)*1028);

分配的內容:查看p,第一字節內容爲data大小8bytes,第二字節內容爲下塊內容所在首地址,即pp所在塊的地址0x804b014,符合預期分配設想

(gdb) x/4a p-4
0x804affc:  0x0 0x8 0x804b014   0x0
(gdb) x/8a p
0x804b00c:  0x0 0x0 0x1010  0x0
0x804b01c:  0x0 0x0 0x0 0x0`
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章