亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

基于malloc與free函數的實現代碼及分析

2020-01-26 16:18:28
字體:
來源:轉載
供稿:網友

  用于內存管理的malloc與free這對函數,對于使用C語言的程序員應該很熟悉。前段時間聽說有的IT公司以“實現一個簡單功能的malloc”作為面試題,正好最近在復習K&R,上面有所介紹,因此花了些時間仔細研究了一下。畢竟把題目做出來是次要的,了解實現思想、提升技術才是主要的。本文主要是對malloc與free實現思路的介紹,藍色部分文字是在個人思考中覺得比較核心的東西;另外對于代碼的說明,有一些K&R上的解釋,使用綠色加亮。

  在研究K&R第八章第五節的實現之前,不妨先看看其第五章第四節的alloc/afree實現,雖然這段代碼主要目的是展示地址運算。

復制代碼 代碼如下:

alloc實現

#define ALLOCSIZE 10000
static char allocbuf[ALLOCSIZE];    /*storage for alloc*/
static char *allocp = allocbuf;    /*next free position*/

char *alloc(int n)
{
    if(allocbuf+ALLOCSIZE - allocp >= n) {
        allocp += n;
        return alloc - n;
    } else
        return 0;
}

void afree(char *p)
{
    if (p >= allocbuf && p<allocbuf + ALLOCSIZE)
        allocp = p;
}

  這種簡單實現的缺點

    1.作為代表內存資源的allocbuf,其實是預先分配好的,可能存在浪費。

    2.分配和釋放的順序類似于棧,即“后進先出”,釋放時如果不按順序會造成異常。

  這個實現雖然比較簡陋,但是依然提供了一個思路。如果能把這兩個缺點消除,就能夠實現比較理想的malloc/free。

  僅僅依靠地址運算來進行定位,是限制分配回收靈活性的原因,它要求已使用部分和未使用部分必須通過某個地址分開成兩個相鄰區域。為了能讓這兩個區域能夠互相交錯,甚至其中還包括一些沒有分配的地址空間,需要使用指針把同類的內存空間連接起來形成鏈表,這樣就可以處理地址不連續的一系列內存空間。但是為什么只連接了空閑空間而不連接使用中的空間?這么問可能出于在對圖中二者類比時的直覺而沒有經過思考,這很簡單,因為沒有必要。前者相互鏈接是為了能夠在內存分配時遍歷所有空閑空間,并且在使用free()回收已使用空間時進行重新插入。而對于使用中的空間,由于我們在分配空間時已經知道它們的地址了,回收時可以直接告訴free(),并不用像malloc()時進行遍歷。

  既然提到了鏈表,可能對數據結構稍有了解的人會立刻寫下一個struct來代表一個內存區域,其中包含一個指向下一個內存區域的指針,但是這個struct的其他成員該怎么寫呢?作為待分配的內存區域,大小是不定的,如果把它聲明為struct的成員變量顯然不妥;如果聲明為一個指向某個其他的區域的指針,這似乎又和上面的直觀表示不相符合。(當然,這么做也是可以實現的,它看上去是介于上圖的兩者之間,把管理結構和實際分配的空間相剝離,在文末我會專門的討論一下這種實現方法)因此,這里仍然把控制結構和空閑空間相分開,但保持它們在內存地址中相鄰,形成下圖的形式,而正由這個特點,我們可以利用對控制結構指針的指針運算來定位對應的內存區域:

  

  對應地,把控制信息定義為Header:

復制代碼 代碼如下:

typedef long Align;/*for alignment to long boundary*/
union header {
    struct {
        union header *ptr; /*next block if on free list*/
        unsigned size; /*size of this block*/
    } s;
    Align x;
};

typedef union header Header;

  使用union而不是直接使用struct的原因是為了地址對齊。這里是long對齊,union的x永遠不會使用。

  這樣,malloc的主要工作就是對這些Header和其后的內存塊的管理。

復制代碼 代碼如下:

malloc()

static Header base;
static Header *freep = NULL;

void *malloc(unsigned nbytes)
{
    Header *p, *prevp;
    unsigned nunits;
    nunits = (nbytes+sizeof(Header)-1)/sizeof(Header) + 1;
    if((prevp = freep) == NULL) { /* no free list */
        base.s.ptr = freep = prevp = &base;
        base.s.size = 0;
    }
    for(p = prevp->s.ptr; ;prevp = p, p= p->s.ptr) {
        if(p->s.size >= nunits) { /* big enough */
            if (p->s.size == nunits)  /* exactly */
                prevp->s.ptr = p->s.ptr;
            else {
                p->s.size -= nunits;
                p += p->s.size;
                p->s.size = nunits;
            }
            freep = prevp;
            return (void*)(p+1);
        }
        if (p== freep) /* wrapped around free list */
            if ((p = morecore(nunits)) == NULL)
                return NULL; /* none left */
    }
}


  實際分配的空間是Header大小的整數倍,并且多出一個Header大小的空間用于放置Header。但是直觀來看這并不是nunits = (nbytes+sizeof(Header)-1)/sizeof(Header) + 1啊?如果用(nbytes+sizeof(Header))/sizeof(Header)+1豈不是剛好?其實不是這樣,如果使用后者,nbytes+sizeof(Header)%sizeof(Header) == 0時,又多分配了一個Header大小的空間了,因此還要在小括號里減去1,這時才能符合要求。

   malloc()第一次調用時建立一個退化鏈表base,只有一個大小是0的空間,并指向它自己。freep用于標識空閑鏈表的某個元素,每次查找時可能發生變化;中間的查找和分配過程是基本的鏈表操作,在空閑鏈表中不存在合適大小的空閑空間時調用morecore()獲得更多內存空間;最后的返回值是空閑空間的首地址,即Header之后的地址,這個接口與庫函數一致。

復制代碼 代碼如下:

morecore()

#define NALLOC 1024    /* minimum #units to request */
static Header *morecore(unsigned nu)
{
    char *cp;
    Header *up;
    if(nu < NALLOC)
        nu = NALLOC;
    cp = sbrk(nu * sizeof(Header));
    if(cp == (char *)-1)    /* no space at all*/
        return NULL;
    up = (Header *)cp;
    up->s.size = nu;
    free((void *)(up+1));
    return freep;
}


  morecore()從系統申請更多的可用空間,并加入。由于調用了sbrk(),系統開銷比較大,為避免morecore()本身的調用次數,設定了一個NALLOC,如果每次申請的空間小于NALLOC,就申請NALLOC大小的空間,使得后續malloc()不必每次都需要調用morecore()。對于sbrk(),在后面會有介紹。

  這里有個讓人驚訝的地方:malloc()調用了morecore(),morecore()又調用了free()!第一次看到這里時可能會覺得不可思議,因為按照慣性思維,malloc()和free()似乎應該是相互分開的,各司其職啊?但請再思考一下,free()是把空閑鏈表進行擴充,而malloc()在空閑鏈表不足時,從系統申請到更多內存空間后,也要先把它們轉化成空閑鏈表的一部分,再進行利用。這樣,malloc()調用free()完成后面的工作也是順理成章了。根據這個思想,后面是free()的實現。在此之前,還有幾個morecore()自身的細節:

  1.如果系統也沒有空間可以分配,sbrk()返回-1。cp是char *類型,在有的機器上char無符號,這里需要一次強制類型轉換。

  2.morecore()調用的返回值看上去比較奇怪,別擔心,freep會在free()中修改的。使用這個返回值也是為了在malloc()里的判斷、p = freep的再次賦值的語句能夠緊湊。

復制代碼 代碼如下:

free()

void free(void *ap)
{
    Header *bp,*p;
    bp = (Header *)ap -1; /* point to block header */
    for(p=freep;!(bp>p && bp< p->s.ptr);p=p->s.ptr)
        if(p>=p->s.ptr && (bp>p || bp<p->s.ptr))
            break;    /* freed block at start or end of arena*/
    if (bp+bp->s.size==p->s.ptr) {    /* join to upper nbr */
        bp->s.size += p->s.ptr->s.size;
        bp->s.ptr = p->s.ptr->s.ptr;
    } else
        bp->s.ptr = p->s.ptr;
    if (p+p->s.size == bp) {     /* join to lower nbr */
        p->s.size += bp->s.size;
        p->s.ptr = bp->s.ptr;
    } else
        p->s.ptr = bp;
    freep = p;
}


   free()首先定位要釋放的ap對應的bp與空閑鏈表的相對位置,找到它的的最近的上一個和下一個空閑空間,或是當它在整個空閑空間的前面或后面時找到空閑鏈表的首尾元素。注意,由于malloc()的分配方式和free()的回收時的合并方式(下文馬上要提到),可以保證整個空閑空間的鏈表總是從低地址逐個升高,在最高地址的空閑空間回指向低地址第一個空閑空間。

  定位后,根據要釋放的空間與附近空間的相鄰性,進行合并,也即修改對應空間的Header。兩個if并列可以使得bp可以同時與高地址和低地址空閑空間結合(如果都相鄰),或者進行二者之一的合并,或者不合并。

  完成了這三部分代碼后(注意放到同一源文件中,sbrk()需要#include <unistd.h>),就可以使用了。當然要注意,命名和stdlib.h中的同名函數是沖突的,可以自行改名。

  第一次審視源碼,會發現很多實現可能原先并沒有想到:Header的結構和對齊填充、空間的取整、鏈表的操作和初始化(邊界情況)、malloc()對free()的調用、由malloc()和free()暗中保證的鏈表地址有序等等,確實很值得玩味。另外再附上前文中提到的兩個問題還有一些補充問題的簡單思考

1.Header與空閑空間相剝離,Header中包含一個指向其空閑空間的指針

  這樣做未必不可,相應地算法需要改動。同時,由于Header和空閑空間不再相鄰,sbrk()獲得的空間也應該包含Header的部分,內存的分布可能會更加瑣碎。當然,這也可能帶來好處,即用其他數據結構對鏈表進行管理,比如按大小進行hash,這樣查找起來更快。

2.關于sbrk()

  sbrk()也是庫函數,它能使堆往棧的方向增長,具體可以參考:brk(), sbrk() 用法詳解。

3.可以改進的方

  空閑空間的尋找是線性的,查找過程在內存分配中可以看作是循環首次適應算法,在某些情況下可能很慢;如果再建立一個數據結構,如hash表,對不同大小的空間進行索引,肯定可以加快查找本身,并且能實現一些算法,比如最佳匹配。但查找加快的代價是,修改這個索引會占用額外的時間,這是需要權衡的。

  morecore()中的最小分配空間是宏定義,在實際使用中完全可以作為參數傳遞,根據需要設定最小分配下限。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久精品视频99| 欧美主播福利视频| 日韩欧美在线视频| 国产91免费看片| 亚洲天堂网站在线观看视频| 欧美在线影院在线视频| 日韩免费av一区二区| 91亚洲午夜在线| 亚洲精品www| 欧美国产视频一区二区| 日韩最新av在线| 亚洲男人天堂2023| 久久综合色影院| 日本久久久久久久久久久| 亚洲免费一级电影| 国产精品成人av在线| 亚洲国产日韩欧美在线99| 久久久免费av| 日韩精品视频中文在线观看| 精品无人国产偷自产在线| 在线播放国产一区中文字幕剧情欧美| 日韩av在线网站| 911国产网站尤物在线观看| 欧美大片免费观看在线观看网站推荐| 久久综合亚洲社区| 法国裸体一区二区| 久久久久久久久久久免费精品| 92裸体在线视频网站| 影音先锋日韩有码| 亚洲第一网站免费视频| 国产精品看片资源| 中文字幕精品www乱入免费视频| 成人激情黄色网| 亚洲激情小视频| 国产自产女人91一区在线观看| 一个色综合导航| 91夜夜未满十八勿入爽爽影院| 日韩av综合网| 26uuu日韩精品一区二区| 国产在线观看不卡| 午夜精品久久久久久久男人的天堂| 久久91亚洲人成电影网站| 欧美国产日韩二区| 欧美激情综合色综合啪啪五月| 国产精品一区二区久久精品| 亚洲第一页在线| 91精品久久久久久久久青青| 一区二区三区视频观看| 日韩久久精品成人| 欧美理论片在线观看| 亚洲欧美国产一区二区三区| 久久久视频免费观看| 日韩精品久久久久久久玫瑰园| 亚洲午夜精品久久久久久性色| 亚洲精品久久7777777| 精品国产91乱高清在线观看| 久久免费国产视频| 欧美wwwwww| 懂色aⅴ精品一区二区三区蜜月| 一区二区亚洲精品国产| 日韩成人网免费视频| 精品动漫一区二区三区| 国产成人在线亚洲欧美| 日韩性xxxx爱| 国产视频999| 欧美成在线视频| 久久夜色撩人精品| 日韩成人xxxx| 欧美精品一区在线播放| 欧美激情小视频| 欧美日韩国产第一页| 国产主播喷水一区二区| 成人高h视频在线| 午夜精品久久久久久99热| 久久久久久国产精品三级玉女聊斋| 国产视频精品免费播放| 欧美精品在线观看| 亚洲a级在线观看| 亚洲欧美激情精品一区二区| 久久精品视频亚洲| 国产精品爽爽ⅴa在线观看| 精品国产精品三级精品av网址| 岛国av一区二区| www.亚洲一二| 日韩在线视频网站| 国产欧美精品日韩精品| 亚洲成在人线av| yellow中文字幕久久| 黄网动漫久久久| 91精品国产高清久久久久久久久| 蜜臀久久99精品久久久久久宅男| 欧美黑人又粗大| 亚洲欧洲自拍偷拍| 日韩av电影中文字幕| 日韩成人免费视频| 欧美特级www| 精品自在线视频| 色妞色视频一区二区三区四区| 亚洲男人天堂2023| 精品免费在线观看| 亚洲精品456在线播放狼人| 亚洲欧美中文在线视频| 日韩欧美在线字幕| 欧美视频在线免费看| 精品国内产的精品视频在线观看| 国产精品成人一区二区| 亚洲精品电影在线观看| 亚洲一区av在线播放| 国产精品久久久久999| 欧美三级欧美成人高清www| 俺去了亚洲欧美日韩| 成人激情视频免费在线| 亚洲人成电影在线观看天堂色| 97精品视频在线| 亚洲精品videossex少妇| 国产日韩欧美中文| 国产精品美腿一区在线看| 国产精品入口福利| 亚洲精品一区久久久久久| 色yeye香蕉凹凸一区二区av| 最近2019年好看中文字幕视频| 国产亚洲精品一区二555| 日韩在线小视频| 欧美极品少妇xxxxⅹ裸体艺术| 久久全国免费视频| 国产精品入口日韩视频大尺度| 久久久久久亚洲精品| 亚洲人成电影在线| 亚洲第一av网站| 国产精品亚洲аv天堂网| 性色av一区二区三区红粉影视| 国产日本欧美一区二区三区| 久久视频在线看| 色播久久人人爽人人爽人人片视av| 国内揄拍国内精品少妇国语| 日韩av电影在线网| 狠狠做深爱婷婷久久综合一区| 在线观看亚洲视频| 日本a级片电影一区二区| 欧美日韩亚洲激情| 国产亚洲精品综合一区91| 欧美在线不卡区| 日韩一级裸体免费视频| 亚洲精品中文字幕有码专区| 日韩欧美高清视频| 欧美性极品xxxx做受| 91中文字幕在线观看| 国产精品综合久久久| 精品国产一区二区三区四区在线观看| 亚洲女同性videos| 成人精品一区二区三区电影免费| 日本不卡高字幕在线2019| 精品美女国产在线| 91精品国产自产91精品| 清纯唯美日韩制服另类| 久久精品91久久久久久再现| 国产69精品久久久久9| 日本a级片电影一区二区| 国产精品香蕉av| 九九热精品在线| 91色精品视频在线| 91精品久久久久久综合乱菊| 久久视频免费观看| 亚洲精品一区二区网址|