zoukankan      html  css  js  c++  java
  • malloc的实现

      在做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时删除。这个方法主要参考这里

  • 相关阅读:
    【题解】洛谷 P3942 将军令【20201017 CSP 模拟赛】【贪心】
    ASP.NET上传文件的三种基本方法
    Android 最火的快速开发框架XUtils
    asp.net 上传文件到一般处理程序中
    Android版本:使用findViewById()用字符串/在一个循环
    android 调用系统图库查看指定路径的图片
    Android中实现日期时间选择器(DatePicker和TimePicker)
    Android自定义ListView的Item无法响应OnItemClick的解决办法
    Android开发配置,消除SDK更新时的“https://dl-ssl.google.com refused”异常
    mysql 修改密码
  • 原文地址:https://www.cnblogs.com/tonychen-tobeTopCoder/p/5450869.html
Copyright © 2011-2022 走看看