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之后的空间属于分配出来的内存,该块被分配之后有效.

  管理空闲内存由MHeap结构维护,该结构如下

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];另一份返回.

      释放过程是,先判断相邻两块是否空闲,并且长度相等,如果是,则合并.之后将内存插入空闲列表.

全部代码如下:

#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);
}

 

posted @ 2013-12-25 20:00  一零  阅读(358)  评论(0编辑  收藏  举报