码迷,mamicode.com
首页 > 其他好文 > 详细

malloc的实现

时间:2016-05-01 19:15:06      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:

  在做csapp的malloc实验,一开始是按照书上的隐式链表法,发现得分很低。这种方法确实很挫,需要遍历一遍以找到合适的空闲块。于是我想到《STL源码剖析》中stl的内存池,感觉应该可以用类似的方法做,因为malloc要做的事情实际就是为了防止内存碎片和减少系统调用,实际就是一个内存池。但是书上介绍的stl的内存池是没有边界区块的,也就是没办法合并空闲区块,这样可能产生过多的外部碎片。所以我最终的做法是大体上采用stl的方法,再加上边界区块,以方便合并空闲区块。

  首先是根据需要的大小在freelist中找到合适的位置

int getListOffset(size_t size)  {
    size_t n = -4;
     while((size = size>>1))
        ++n;
    if(n>16)
        return 16;
    if(n<0)
        return 0;
    return n;
}

freelist数组在初始化时创建,将指向空闲块的指针插入freelist的操作如下

/*
 * insert_list - 将free block插入到相应大小的free list中, 插入位置为表头
 */
void insert_list(void *bp)
{
    int index;
    size_t size;
    size = GET_SIZE(HDRP(bp));
    index = getListOffset(size);

    if (GET_PTR(heap_listp + WSIZE * index) == NULL) {
        PUT_PTR(heap_listp + WSIZE * index, bp);
        PUT_PTR(bp, NULL);
        PUT_PTR((unsigned int *)bp + 1, NULL);
    } else {
        PUT_PTR(bp, GET_PTR(heap_listp + WSIZE * index));
        PUT_PTR(GET_PTR(heap_listp + WSIZE * index) + 1, bp);  
        PUT_PTR((unsigned int *)bp + 1, NULL);
        PUT_PTR(heap_listp + WSIZE * index, bp);
    }
}

 可以看出,空闲块的前8个字节用来存放指向freelist对应位置的指针和指向下一个相同大小的空闲块的指针。当执行malloc时,这两个指针会被清除

/*
 * place - place the requested block at the beginning of the free block
 */
void place(void *bp, size_t asize)
{
    size_t csize = GET_SIZE(HDRP(bp));
    delete_list(bp);
    if ((csize - asize) >= (2 * DSIZE)) {
        PUT(HDRP(bp), PACK(asize, 1));  
        PUT(FTRP(bp), PACK(asize, 1));
        bp = NEXT_BLKP(bp);
        PUT(HDRP(bp), PACK(csize - asize, 0));
        PUT(FTRP(bp), PACK(csize - asize, 0));
        insert_list(bp);
    } else {
        PUT(HDRP(bp), PACK(csize, 1));
        PUT(FTRP(bp), PACK(csize, 1));
    }
}

delete_list的实现如下

/* 
 * delete_list - 删除链表结点
 */
void delete_list(void *bp)
{
    int index;
    size_t size;
    size = GET_SIZE(HDRP(bp));
    index = getListOffset(size);
    if (GET_PTR(bp) == NULL && GET_PTR((unsigned int *)bp + 1) == NULL) { 
        /* 链表中唯一结点 */
        PUT_PTR(heap_listp + WSIZE * index, NULL);
    } else if (GET_PTR(bp) == NULL && GET_PTR((unsigned int *)bp + 1) != NULL) {
        /* 链表中最后一个结点, 不是唯一一个 */
        PUT_PTR(GET_PTR((unsigned int *)bp + 1), NULL);
    } else if (GET_PTR(bp) != NULL && GET_PTR((unsigned int *)bp + 1) == NULL){
        /* 链表中第一个结点, 不是唯一一个 */
        PUT_PTR(heap_listp + WSIZE * index, GET_PTR(bp));
        PUT_PTR(GET_PTR(bp) + 1, NULL);
    } else if (GET_PTR(bp) != NULL && GET_PTR((unsigned int *)bp + 1) != NULL) {
        /* 链表中的中间结点 */
        PUT_PTR(GET_PTR((unsigned int *)bp + 1), GET_PTR(bp));
        PUT_PTR(GET_PTR(bp) + 1, GET_PTR((unsigned int*)bp + 1));
    }
}

这种方法很巧妙,不需要额外的空间维护freelist,需要的空间只是在初始化时创建的freelist头,其它指针只存在于空闲块中,并在malloc时删除。这个方法主要参考这里

malloc的实现

标签:

原文地址:http://www.cnblogs.com/tonychen-tobeTopCoder/p/5450869.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!