实现malloc-free用来管理64k内存

本文探讨了如何实现一个malloc-free内存管理系统,用于管理64k的内存。解决思路包括使用union来区分已分配和未分配的内存,避免碎片的splice函数,以及在分配和释放内存时的策略。通过测试20k内存来验证实现,并引发对于是否需要自定义内存分配器的讨论。
摘要由CSDN通过智能技术生成

问题的引入

实现malloc-free,用来管理64k的内存这是一道面试题,也是一道很好的设计


解决思路

1.malloc(size_t size), free(void *p)是用户api, 释放的时候需要知道释放空间的大小,并且需要放入到一个空闲链表里面去,可以这样设计

typedef struct item{
    uint16_t size;
    union {
        char mem[4];
        struct item *next;
    }mn;
}__attribute__ ((packed)) item;

2.采用union,如果分配给用户,则为可以使用内存,加入到空闲链表,则为链表指针。这里的指针大小为4个字节,因此分配给用户的最小长度为4字节,如果用户申请的长度小于4个字节,应该分配4个字节。

如果为16位机器,则应该将联合体改为union {char mem[2];struct item *next;}mn;

3.为了避免内存碎片,这里需要将释放的两个相邻的区域拼接成一个较大的空间,设计一个splice函数。

4.申请,首先找到第一个比申请内存大的空间,然后划分一部分分配给用户,划分函数为cut.

实现

define ITEM_SIZE (sizeof(item) - sizeof(void *))
typedef struct item{
    uint16_t size;
    union {
        char mem[4];
        struct item *next;
    }mn;
}__attribute__ ((packed)) item;

static item *freelist=NULL;
void init(void *memory, uint16_t size) 
{
    assert(memory != NULL && size > sizeof(item));

    freelist = (item *) memory;
    freelist->mn.next = NULL;
    freelist->size = size - ITEM_SIZE;
}

static bool cut(item *it, uint16_t size, item **n)
{
    assert(it != NULL && n != NULL);

    if((uint16_t) (it->size - size) < (uint16_t) sizeof(item))
        return false;

    *n = (item *)(it->mn.mem + size);
    (*n)->size = it->size - size - ITEM_SIZE;
    (*n)->mn.next = it->mn.next;
    it->size = size;
    return true;
}

注意item的定义采用的是联合union,使用非常方便

static void splice(item *left, item *right)
{
    if(left == NULL || right == NULL)
        return ;
    char *start = left->mn.mem + left->size;
    if(start != (char *)right)
        return ;
    left->size = left->size + right->size + ITEM_SIZE;
    left->mn.next = right->mn.next;
}

分配算法

首先查看分配的空间是否小于4,如果小于,则修改为4,便利空闲链表,找到地一个大于申请空间的块,如果可以cut,就cut一部分,不能cut,就分配当前块

void * malloc(uint16_t size) 
{

    if(size < 4)
        size = 4;

    item *prev = NULL, *cur = freelist;
    item *n = NULL;

    while(cur != NULL) {
        if(cur->size > size) {
            bool c = cut(cur, size, &n);
            if(c == false)
                n = cur->mn.next;

            if(prev == NULL)
                freelist = n;
            else
                prev->mn.next = n;

            return cur->mn.mem;
        }   
        prev = cur;
        cur = cur->mn.next;
    }   

    return NULL;
}


释放算法,首先将释放的地址左移两个字节,然后转换为item结构,遍历空闲链表,找到地一个item大于插入item的结构,插入item,并且splice

这里需要注意的是当空闲队列为空的情况,或者释放item的地址最大的情况

void free(void *p)
{
    if(p == NULL)
        return ;
    item *cur = freelist, *prev = NULL;
    item *pit = (item *)((char *)p - ITEM_SIZE);
    while(cur != NULL) {

        if(cur > pit) {
            if(prev == NULL) {
                   pit->mn.next = freelist;
                       freelist = pit;
            } else {
                pit->mn.next = prev->mn.next;
                prev->mn.next = pit;
            }

            splice(pit, cur);
            splice(prev, pit);
            return ;
        }
        prev = cur;
        cur = cur->mn.next;
    }

    if(prev == NULL) {
        pit->mn.next = freelist;
        freelist = pit;
    } else {
        pit->mn.next = prev->mn.next;
        prev->mn.next = pit;
    }
    splice(prev, pit);
}


测试---采用20k的内存测试

#define K_1 1024
#define K_64    (K_1 * 20)
char memory[K_64];

        int
main ( int argc, char *argv[] )
{
    init(memory, K_64);

    const int count = 100000;
    void *p[count];
    int len = 0;

    for(int i = 1; i < count; i++) {
        p[len++] = malloc(i);
    }

    for(int i = 0; i < len; i++) {
        free(p[i]);
    }

    len = 0;
    for(int i = 1; i < count; i++) {
        p[len++] = malloc(i % 20 );
    }
    assert(freelist == NULL);

    for(int i = 0; i < len; i = i + 2) {
        free(p[i]);
    }
    for(int i = 1; i < len; i = i + 2) {
        free(p[i]);
    }

    assert(freelist->size == K_64 - ITEM_SIZE);
    assert(freelist->mn.next == NULL);

    printf("sizeof(item):%d\n", sizeof(item));
    return 0;
}               /* ----------  end of function main  ---------- */

演化

有一种观点认为:需要设计自己的内存分配器,比如stl中的内存分配,memcached中的slab分配,leveldb中memtable中内存分配

一种观点认为操作系统中内存管理已经设计的够好了,不需要设计自己的内存分配器


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值