適用於連續資源塊的數組空閑鏈表的演算法

來源:互聯網
上載者:User

如何來管理空閑資源,顯而易見的是組織成一個雙向鏈表,稱作freelist,然後每次從該鏈表上取出一個,釋放的時候再放回去。為了減少片段,最好的策略就是優先分配最近釋放掉的那個,如果能考慮合并的話,類似夥伴系統那樣,就再好不過了,本文給出的是一個通用的可以將資源地圖到一個整型ID的資源分派演算法,完全基於一個數組,不需要記憶體管理,也不需要分配結構體。

組織鏈表的時候,記憶體管理要耗去大量的工作,前向指標和後向指標的修改前提是必須有這些指標。典型的資料結構就是Linux核心的list_head結構體。但是對於靜態類似位元影像的資源並不適合用list_head來組織,因為這類資源本身可以映射到一塊連續的以自然數計數的ID,比較典型的就是磁碟的空閑塊,連續記憶體塊的分配。

既然資源位置是連續的,它就一定能用連續的自然數來表示,那麼所有的資源就可以表示成一個數組了-其映射成自然數的ID的數組,記為ArrayA。

接下來我們需要另外一個數組來表示空閑鏈表,記為ArrayB。

接下來的然後,就是構造ArrayB了...ArrayB的大小等於ArrayA大小加上1,多出來的這個元素可以作為不動點存在,它是不會被分配出去的。ArrayB的元素的大小是ArrayA數組大小佔據位元組數的兩倍,是為了在一個元素中儲存兩個INDEX,比如數組大小可以用8位元據表示,即最多256個元素,那麼ArrayB的元素就應該是2*8這麼大的,舉例說明:

數組大小:short-最多65536個元素

ArrayA的數組定義:int arrayA[MAX];MAX最大65536

ArrayB的數組定義:int arrayB[];int型為兩個short型

結構體形象化表示ArrayB:

#define NUM    8struct freeHL {        short high_preindex; //表示前一個ArrayA數組中索引        short low_nextindex;  //表示後一個ArrayA數組中索引};struct freeHL  freelist[NUM+1];

相當於將ArrayB劈開成了兩半。

然後就可以在連續的數組空間進行連結操作了。實際上這個數組表示的freelist和指標表示的prev,next的freelist是一致的,數組下標也是一個指標,只是在數組表示的freelist中,使用的是相對指標位移而已,表示為下標!

下面就是一個演算法實現問題了,很簡單。在freelist中分配了一個index後,需要修改其前向index的後向index以及後向index的前向index,釋放過程和分配過程相反。代碼如下:

short data[NUM]; //是為ArrayAstruct freeHL  freelist[NUM+1]; /是為ArrayB//表示一個下一個分配的index;unsigned int position = 0;//全域的一次性初始化,注意,如果是序列化到了檔案,//則不能再次初始化了,應該從檔案還原序列化來初始化。void list_init(){        int i = 0, j = -1;        for (; i < NUM+1; i++) {                freelist[i].high_preindex = (i + NUM)%(NUM+1);                freelist[i].low_nextindex = (i + 1)%(NUM+1);        }        position = 0;}//分配介面int nalloc(){        int ret_index = -1, next_index = -1, pre_index = -1;        ret_index = position;    //儲存當前要分配index的前向index        next_index = freelist[position].low_nextindex;    //儲存當前要分配index的後向index        pre_index = freelist[position].high_preindex;    //分配當前index// http://www.bianceng.cn        position = next_index;        if (ret_index == next_index) {                return -1;        }    //更新當前index前向index的後向index        freelist[freelist[ret_index].high_preindex].low_nextindex = next_index;    //更新當前index後向index的前向index        freelist[freelist[ret_index].low_nextindex].high_preindex = pre_index;        return ret_index;}//釋放介面int nfree(unsigned int id){        int pos_pre = -1, pos_next = -1;    //儲存下一個要分配的index的前向index,減少片段以及更加容易命中cache        pos_pre = freelist[position].high_preindex;    //釋放index為id的元素        freelist[pos_pre].low_nextindex = id;        freelist[id].high_preindex = pos_pre;        freelist[id].low_nextindex = position;    //下一個要分配的index為剛釋放的index        position = id;}

下面是一個測試:

int main(int argc, char **argv){        list_init();        int i = 0;        printf("begin\n");        for (; i < NUM+1; i++) {                printf("\n%d \n", nalloc());        }        nfree(5);        nfree(0);        nfree(7);        for (i = 0; i < NUM+1; i++) {                printf("\n%d \n", nalloc());        }        printf("\nend\n");}

這個代碼用在何處呢?前面說過,用在資源可以表示為連續ID的場合,這種場合何在?在《編寫一個UNIX檔案系統》中,我說那個空閑i節點以及空閑塊的分配演算法不好,而上述的方法就可以用,效果比較好,也就是說,將一點點的工作施放於每次分配/釋放的時候,就可以避免在某個時間點做大量的積攢下來的繁重的工作。這個演算法省去了遍曆操作,代價就是佔用了一點連續的地址空間。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.