malloc的實現

  在作csapp的malloc實驗,一開始是按照書上的隱式鏈表法,發現得分很低。這種方法確實很挫,須要遍歷一遍以找到合適的空閒塊。因而我想到《STL源碼剖析》中stl的內存池,感受應該能夠用相似的方法作,由於malloc要作的事情實際就是爲了防止內存碎片和減小系統調用,實際就是一個內存池。可是書上介紹的stl的內存池是沒有邊界區塊的,也就是沒辦法合併空閒區塊,這樣可能產生過多的外部碎片。因此我最終的作法是大致上採用stl的方法,再加上邊界區塊,以方便合併空閒區塊。數組

  首先是根據須要的大小在freelist中找到合適的位置app

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的操做以下spa

/*
 * 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時,這兩個指針會被清除.net

/*
 * 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時刪除。這個方法主要參考這裏code

相關文章
相關標籤/搜索