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

怎甘沉沦 提交于 2020-04-07 12:21:38

问题的引入
实现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中内存分配

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


————————————————
版权声明:本文为CSDN博主「yuan_da_xing」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yuan_da_xing/article/details/8395704

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!