实现自己的malloc

按照上篇文章的思路,自己实现的一个简单malloc:

#include <unistd.h>
#include <stdio.h>

struct header_t  {
    size_t size;               //8B
    unsigned is_free;          //4B
    struct header_t* next;     //8B
};

struct header_t* g_head = NULL;
struct header_t* g_tail = NULL;

struct header_t* get_free_block(size_t size)  {
    struct header_t* curr = g_head;
    while(curr)  {
        if (curr->is_free && curr->size >= size)  {
            return curr;
        }
        curr = curr->next;
    }
    return NULL;
}


void* malloc(size_t size)  {
    if (!size)  {
        return NULL;
    }
    
    struct header_t* header = get_free_block(size);
    if (header)  {
        header->is_free = 0;
        return (void*)(header + 1);
    }
    
    size_t total_size = sizeof(struct header_t) + size;
    void* block = sbrk(total_size);
    if (block == (void*)-1)  {
        return NULL;
    }
    
    header = block;
    header->size = size;
    header->is_free = 0;
    header->next = NULL;
    
    if (g_head == NULL)  {
        g_head = header;
    }
    if (g_tail)  {
        g_tail->next = header;
    }
    
    g_tail = header;
    return (void*)(header + 1);
}

void free(void* block)  {
    if (!block)  {
        return;
    }
    
    struct header_t* header = (struct header_t*)block - 1;
    void* programbreak = sbrk(0);
    
    
    //如果要释放的模块位于链表中的最后一个,则在链表中删除最后一个内存块,并释放内存,否者该内存块只是标记一下为free
    if ((char*)block + header->size == programbreak)  {  //block is the last one in the list
        if (g_head == g_tail)  {     //only one block in the list
            g_head = g_tail = NULL;
        }
        else  {
            struct header_t* tmp = g_head;
            while(tmp)  {
                if (tmp->next == g_tail)  {
                    tmp->next = NULL;
                    g_tail = tmp;
                }
                tmp = tmp->next;
            }
        }
        sbrk(0 - header->size - sizeof(struct header_t));
    }
    else  {
        header->is_free = 1;
    }
}

void* realloc(void* block, size_t size)  {
    if (!block || !size)  {
        return malloc(size);
    }
    struct header_t* header = (struct header_t*)block - 1;
    if (header->size >= size)  {
        return block;
    }
    void* ret = malloc(size);
    if (ret)  {
        memccpy(ret, block, header->size);
        free(block);
    }
    return ret;
}


int main()  
{
    char* p = (char*)malloc(1);
    printf("p is %p\n", p);
    p = (char*)malloc(2);
    printf("p is %p\n", p);
    return 0;
}

代码还算清晰简单,总体的思路是链式内存管理法。分配内存时,先看链表中有没有空闲且足够大小的内存块。没有的话则分配需要大小的内存,加上用来管理内存结点的内存,然后加入到链表中。链表中有空闲的内存块是因为,后面调用free释放内存时,不会里面释放内存,只是加了一个标志位,保存起来供后面的分配使用。

我们注意到,分配内存的时候有所需大小这个参数,为什么释放的时候没有呢?难道不需要知道释放内存的大小吗。如果释放的时候也要知道内存的大小,对开发者而言显得就那么不太友好,因为还要保存分配内存的大小。幸好聪明的开创者门已为我们找到了解决方案,利用内存块管理节点来保存,上面的代码中也是这么做的。

以上的代码只是基本实现了malloc和free函数,但是效率上肯定是不能和glibc的相比的。上面的代码也有很多改进的地方,例如单链表查找的方式,效率过于低下。适配空闲内存块的算法也有很多,比如最先适配,最好适配等等。还有多线程也不支持,有机会再来剖析glibc的malloc即ptmalloc分配算法。

 

参考:

https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/comment-page-1/

https://arjunsreedharan.org/

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值