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