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