编写内存分配器

编写一个简单的分配器需要考虑以下问题:
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);        //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);
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值