编写一个简单的分配器需要考虑以下问题:
1、空闲块的组织方式,选用的是隐式空闲链表
2、如何放置一个新分配的块,采用的是首次适配策略
3、如何合并空闲块
块的格式:使用边界标记的堆块的格式
定义4个字节为一个字,头部和脚部各一个字,内容相同。分别为块的大小和块的分配状态。采用双字对齐,因此最小块大小为16字节。脚部是为了便于合并空闲块而存在。
堆的格式
序言块和结尾块的存在也是为了便于合并。
我们的内存分配器运行于由memlib.c提供的内存模型之上。
memlib.c
#include
#include
static char *memHeap; //首地址
static char *memBrk; //尾后地址
static char *memMaxAddr; //最大边界地址
static const unsigned int MAX_HEAP=1<<24;
void mem_init()
{
memHeap=(char*)(malloc(MAX_HEAP));
memBrk=memHeap;
memMaxAddr=(char*)(memHeap+MAX_HEAP);
}
//分配额外的内存
void *mem_sbrk(int incr)
{
char *old_brk=memBrk;
if((incr<0)||((memBrk+incr)>memMaxAddr))//拒绝堆收缩请求和检测内存耗尽
{
std::cout<<"error";
return (void*)-1;
}
memBrk+=incr;
return (void*)old_brk;
}
头文件提供一些简单的函数和函数接口
#include
class mm
{
public:
mm()
{mmInit();}
void mmFree(void *bp) //free
{
size_t size=getSize(hdrp(bp));
put(hdrp(bp),pack(size, 0)); //标记为空闲块
put(ftrp(bp),pack(size, 0));
coalesce(bp); //合并
}
void *mmMalloc(size_t size); //malloc
private:
static const unsigned int WSIZE=4; //字长为4字节
static const unsigned int DSIZE=8;
static const unsigned int CHUNKSIZE=1<<12; //默认分配块的大小
char *heapListP; //指向分配的第一个块,序言块
//方便操作的一组函数
unsigned int pack(unsigned int size,unsigned int alloc)
{return (size|alloc);}
unsigned int get(void *p)
{return *((unsigned int *)(p));}
void put(void *p,unsigned int val)
{*((unsigned int *)(p))=val;}
unsigned int getSize(void *p)
{return get(p)&(~0x7);}
unsigned int getAlloc(void *p)
{return get(p)&(0x1);}
char *hdrp(void *bp)
{return ((char*)bp-WSIZE);}
char *ftrp(void *bp)
{return ((char*)bp+getSize(hdrp(bp))-DSIZE);}
char *nextBlkP(void *bp)
{return ((char*)bp+getSize(hdrp(bp)));}
char *prevBlkP(void *bp)
{return ((char*)bp-getSize((char*)bp-DSIZE));}
int mmInit();//初始化堆
void *extendHeap(size_t words);//扩展堆,初始化的时候调用和找不到合适空闲块时调用
void *coalesce(void *bp); //合并空闲块
void *findFit(size_t size); //找到合适的分配块
void place(void *bp,size_t size); //放置分配块
};
cpp文件
#include "mm.hpp"
void *mem_sbrk(int incr);
//初始化堆
int mm::mmInit()
{
heapListP=(char*)mem_sbrk(4*WSIZE);
if(heapListP==(void*)-1)
return -1;
put(heapListP, 0); //起始位置,不使用的填充字
put(heapListP+(1*WSIZE),pack(DSIZE, 1)); //序言块
put(heapListP+(2*WSIZE),pack(DSIZE, 1));
put(heapListP+(3*WSIZE),pack(0, 1)); //结尾块
heapListP+=(2*WSIZE); //指向序言块
if(extendHeap(CHUNKSIZE/WSIZE)==nullptr) //初始分配一个默认块
return -1;
return 0;
}
//扩展堆
void *mm::extendHeap(std::size_t words)
{
size_t size;
void * blockptr;
size=(words%2)?(words+1)*WSIZE:words*WSIZE;//双字对齐
if((long)(blockptr=mem_sbrk(size))==-1)
return nullptr;
put(hdrp(blockptr),pack(size, 0));//结尾块变成分配块的头部
put(ftrp(blockptr),pack(size, 0));//分配块的脚部
put(hdrp(nextBlkP(blockptr)),pack(0, 1)); //新的结尾块
return coalesce(blockptr);//合并空闲块
}
//合并空闲块,一共四种情况。
void *mm::coalesce(void *bp)
{
size_t prevAlloc=getAlloc(hdrp(prevBlkP(bp)));
size_t nextAlloc=getAlloc(hdrp(nextBlkP(bp)));
size_t size=getSize(hdrp(bp));
if(prevAlloc&&nextAlloc)
{
return bp;
}
else if(prevAlloc&&(!nextAlloc))
{
size+=getSize(hdrp(nextBlkP(bp)));
put(hdrp(bp), pack(size, 0));
put(ftrp(bp), pack(size, 0));
}
else if(!prevAlloc&&nextAlloc)
{
size+=getSize(hdrp(prevBlkP(bp)));
bp=prevBlkP(bp);
put(hdrp(bp), pack(size, 0));
put(ftrp(bp), pack(size, 0));
}
else
{
size+=getSize(hdrp(nextBlkP(bp)))+getSize(hdrp(prevBlkP(bp)));
bp=prevBlkP(bp);
put(hdrp(bp), pack(size, 0));
put(ftrp(bp), pack(size, 0));
}
return bp;
}
//动态分配内存
void *mm::mmMalloc(size_t size)
{
size_t asize;
size_t extendSize;
void *bp;
if(size==0)
return nullptr;
if(size<=DSIZE) //最小块大小为16字节
asize=2*DSIZE;
else
asize=DSIZE*((size+DSIZE+(DSIZE-1))/DSIZE); //双字对齐
if((bp=findFit(asize))!=nullptr)
{
place(bp, asize);
return bp;
}
extendSize=asize>CHUNKSIZE?asize:CHUNKSIZE;
if((bp=extendHeap(extendSize/WSIZE))==nullptr)
return nullptr;
place(bp, asize);
return bp;
}
//遍历块首次适配
void *mm::findFit(size_t size)
{
char * bp=heapListP+DSIZE;
while (getSize(hdrp(bp)))
{
if(getAlloc(hdrp(bp)))
bp=nextBlkP(bp);
else if (getSize(hdrp(bp))>=size)
return bp;
else
bp=nextBlkP(bp);
}
return nullptr;
}
//放置块
void mm::place(void *bp,size_t asize)
{
size_t size=getSize(hdrp(bp));
if(size-asize<2*DSIZE)
{
put(hdrp(bp), pack(size, 1));
put(ftrp(bp), pack(size, 1));
}
else
{
put(hdrp(bp), pack(asize, 1));
put(ftrp(bp), pack(asize, 1));
void *nextBp=nextBlkP(bp);
put(hdrp(nextBp), pack(size-asize, 0));
put(ftrp(nextBp), pack(size-asize, 0));
}
}
main.c
#include "mm.hpp"
void mem_init();
int main()
{
mem_init();
mm memory;
int *p=(int*)memory.mmMalloc(sizeof(int)*100);
memory.mmFree(p);
}