malloc的一個實現

malloc的一個簡單的實現:數組

  空閒內存塊,和已分配的內存經由以下結構管理函數

struct _MObject{
    MObject     *before;    /*!指向上一個對象,由上一個對象維護(什麼,這個對象的成員由上個對象維護?)!*/
    long        busy;
    size_t      length;     /*! 整個對象長度,包括prev,length,所佔空間在內 !*/
    union{
        struct{MObject *next,*prev;};   /*! 空閒對象鏈 !*/
        int8_t  chunk[0];               /*! 對象管理的數據塊 !*/
    };
};

        befora指向與當前對象相鄰在並在該對象以前的那個內存對象,用來快速找到該對象,以便進行合併.該指針由相鄰的那個對象維護,本對象只是內對其進行讀.busy字段用來判斷該塊內存是否已經分配:M_BUSY已分配,M_UNBUSY:沒有分配.length字段包括MObject所佔空間在內.next,prev用於空閒鏈表,只有該塊未分配時有效,若是已經分配了,則區域數據屬於用戶數據.chunk以後的空間屬於分配出來的內存,該塊被分配以後有效.oop

  管理空閒內存由MHeap結構維護,該結構以下spa

struct _MHeap{
    MObject *objectList[NR_MOBJECT];
    size_t  length;
    int8_t  chunk[0];
}*heap = NULL;

      objectList是log2(塊長度)爲下標的空閒鏈表指針數組,例如,下標爲objectList[4]就是長度爲2^4,16字節的空閒內存鏈表.length是整個管理內存塊(已分配+未分配)總長度,chunk以後就是管理內存區.指針

 

  首先,管理程序調用realizeMHeap來實例化一個可管理內存區,該函數只能調用一次.以後就能夠調用Malloc和Free來動態使用內存.Malloc將要申請的長度加上MObject結構 - sizeof(void*);來計算獲得一個合適的值log2n,而後調用getMObject()查找一個合適的塊,getbject先查看objectList[log2n]是否有空閒內存,若是有,則將objectList[log2n]刪除,刪除操做會用objectList[log2n]->next放入objectList[log2n].以後設置busy,將老的objectList[log2n]返回.若是沒有找到則遞歸調用getMObject(log2n + 1);將getMObject反回內存,一分爲2,將其一份插入objectList[log2n];另外一份返回.code

      釋放過程是,先判斷相鄰兩塊是否空閒,而且長度相等,若是是,則合併.以後將內存插入空閒列表.對象

所有代碼以下:blog

#include    <stdio.h>
#include    <stdlib.h>
#include    <stdint.h>
#include    <string.h>

#define mm_error(fmt,...)   fprintf(stdout,"[MALLOC] : "fmt"\n",##__VA_ARGS__)
#define mm_warning(fmt,...) fprintf(stdout,"[MALLOC] : "fmt"\n",##__VA_ARGS__)

#ifndef isNullp
#define isNullp(x)  (!(x))
#endif

#define M_BUSY      (!0)
#define M_UNBUSY    (0)

#ifndef typeof
#define typeof  __typeof__
#endif

#define offsetof(TYPE,MEMBER)   ((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr,type,member)   ({                  \
        const typeof( ((type *)0)->member) *__mptr = (ptr); \
        (type *)( (char *)__mptr - offsetof(type,member)); })

#define log2(n) ({                      \
        int _v;                         \
        for(_v = 0;n > (1 << _v);_v++); \
        _v; })
#define exp2(n) (1 << n)

#define NR_MOBJECT              32
#define HEAP_LIMIT              ((MObject*)(((void*)heap->chunk) + heap->length))
#define AFTER(x)                ((MObject*)(((void*)(x)) + (x)->length))
#define isHeapOverflow(x)       (AFTER(x) >= HEAP_LIMIT)
#define isLog2Overflow(x)       ((x) >= NR_MOBJECT || (x) < 0)

#define _TAIL(x)    ({          \
        if(!isHeapOverflow(x)){             \
            AFTER(x)->before = x;   \
        }})

#define exit(n) while(n)

typedef struct _MObject MObject;
typedef struct _MHeap   MHeap;

struct _MObject{
    MObject     *before;    /*!指向上一個對象,由上一個對象維護(什麼,這個對象的成員由上個對象維護?)!*/
    long        busy;
    size_t      length;     /*! 整個對象長度,包括prev,length,所佔空間在內 !*/
    union{
        struct{MObject *next,*prev;};   /*! 空閒對象鏈 !*/
        int8_t  chunk[0];               /*! 對象管理的數據塊 !*/
    };
};

struct _MHeap{
    MObject *objectList[NR_MOBJECT];
    size_t  length;
    int8_t  chunk[0];
}*heap = NULL;

/*******************************************************************************
 *  delMObject
 *      從鏈表裏面刪除節點,並返回被刪除的節點
 *  ARGS:
 *      mobject     將被刪除的節點
 * *****************************************************************************/
static inline MObject *delMObject(MObject *mobject){
    MObject *next,*prev;
    if(isNullp(mobject)){
        mm_error("Trying to remove an empty object");
        return NULL;
    }
    next = mobject->next;
    prev = mobject->prev;
    if(!isNullp(prev)){
        prev->next = next;
    }else{
        heap->objectList[log2(mobject->length)] = next;
    }
    if(!isNullp(next)){
        next->prev = prev;
    }
    mobject->busy = M_BUSY;
    return mobject;
}

static inline MObject *insertMObject(MObject *head,MObject *new){
    if(isNullp(new)){
        mm_error("Trying to insert an empty object");
        return NULL;
    }
    new->next = head;
    new->prev = NULL;
    new->busy = M_UNBUSY;
    if(!isNullp(head)){
        head->prev = new;
    }
    return new;
}

static inline MObject *splitMObject(MObject *mobject){
    int log2n;
    size_t nl;
    MObject *tail;
    if(isNullp(mobject)){
        mm_error("Trying to split an empty object");
        return NULL;
    }
    nl = mobject->length >> 1;
    log2n = log2(nl);
    tail = ((void*)mobject) + nl;
    *tail = (MObject){
        .before = mobject,
        .length = nl,
    };
    _TAIL(tail);
    heap->objectList[log2n] = insertMObject(heap->objectList[log2n],tail);
    mobject->length = nl;
    return mobject;
}

static inline MObject *mergerMObject(MObject *head,MObject *tail){
    if(isNullp(head) || isNullp(tail)){
        mm_error("Trying to merger emptry objects");
        exit(1);
    }
    if(AFTER(head) != tail){
        mm_error("Trying to merger noncontiguous objects\nhead : %p length : %x\ntail : %p length : %x",head,head->length,tail,tail->length);
        exit(1);
    }
    if(head->length == tail->length){
        head->length <<= 1;
        _TAIL(head);
    }
    return head;
}

static MObject *getMObject(int log2n){
    MObject *mobject;
    if(isLog2Overflow(log2n)){
        return NULL;
    }
    mobject = heap->objectList[log2n];
    if(mobject){
        mobject = delMObject(mobject);
        return mobject;
    }
    mobject = getMObject(log2n + 1);
    if(isNullp(mobject)){
        return NULL;
    }
    return splitMObject(mobject);
}

int realizeMHeap(size_t length){
    int log2n;
    MObject *mobject;
    if(heap){
        mm_error("Heap already exists");
    }
    length += (sizeof(MHeap));
    log2n = log2(length);
    if(isLog2Overflow(log2n)){
        mm_error("Can only create heap 0 ~ %d,but requesting %d",exp2(31) - sizeof(MHeap),length);
        return -1;
    }
    heap = malloc(sizeof(MHeap) + exp2(log2n));
    if(isNullp(heap)){
        mm_error("oops,the memory is full,tell your boss");
        return -1;
    }
    memset(heap,0,sizeof(MHeap) + exp2(log2n));
    heap->length = exp2(log2n);
    mobject = (MObject *)heap->chunk;
    *mobject = (MObject){
        .before = NULL,
        .length = exp2(log2n),
        .busy   = M_UNBUSY,
        .next   = NULL,
        .prev   = NULL,
    };
    heap->objectList[log2n] = mobject;
    return 0;
}

void *Malloc(size_t length){
    int log2n;
    MObject *mobject;
    length += (sizeof(MObject) - sizeof(struct{MObject *next,*prev;}));
    log2n = log2(length);
    if(isLog2Overflow(log2n)){
        mm_error("Can only alloc  0 ~ %d,but requesting %d",exp2(31) - sizeof(MHeap) - sizeof(MObject),length);
        return NULL;
    }
    mobject = getMObject(log2n);
    if(mobject){
        return mobject->chunk;
    }
    return NULL;
}

void Free(void *ptr){
    int log2n;
    MObject *mobject = container_of(ptr,MObject,chunk);
    if(isNullp(ptr) || mobject > (MObject*)HEAP_LIMIT || mobject < (MObject*)heap->chunk){
        mm_error("Trying to free non-heap memory %p",ptr);
        return ;
    }
    if(!isNullp(mobject->before)){
        MObject *head = mobject->before;
        if((head->busy == M_UNBUSY)){
            head = delMObject(head);
            mobject = mergerMObject(head,mobject);
        }
    }
    if(!isHeapOverflow(mobject)){
        MObject *tail = AFTER(mobject);
        if(tail->busy == M_UNBUSY){
            tail = delMObject(tail);
            mobject = mergerMObject(mobject,tail);
        }
    }
    log2n = log2(mobject->length);
    heap->objectList[log2n] = insertMObject(heap->objectList[log2n],mobject);
}
相關文章
相關標籤/搜索