编写内存分配器

来源:互联网 发布:淘宝rol是指什么 编辑:程序博客网 时间:2024/05/18 01:17

编写一个简单的分配器需要考虑以下问题:
1、空闲块的组织方式,选用的是隐式空闲链表
2、如何放置一个新分配的块,采用的是首次适配策略
3、如何合并空闲块

块的格式:使用边界标记的堆块的格式

这里写图片描述

定义4个字节为一个字,头部和脚部各一个字,内容相同。分别为块的大小和块的分配状态。采用双字对齐,因此最小块大小为16字节。脚部是为了便于合并空闲块而存在。

堆的格式

这里写图片描述

序言块和结尾块的存在也是为了便于合并。

我们的内存分配器运行于由memlib.c提供的内存模型之上。
memlib.c

#include <cstdlib>#include <iostream>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<cstddef>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);        //mallocprivate:    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);}