標籤:
lnux核心的malloc實現(Oracle的cache buffer影子)
本文原創為freas_1990,轉載請標明出處:http://blog.csdn.net/freas_1990/article/details/12845059
本文介紹一下malloc的原理,對mm感興趣(或者對Oracle internal實現感興趣)的同學能在本文找到感興趣的內容。
malloc主要由兩個結構體做支撐。
struct bucket_desc { /* 16 bytes */ void *page; struct bucket_desc *next; void *freeptr; unsigned short refcnt; unsigned short bucket_size;};
這個結構體是一個bucket descriptor。所有的object會通過鏈錶鏈接起來。
struct _bucket_dir {/* 8 bytes */intsize;struct bucket_desc*chain;};
這是bucket的目錄。
我畫了兩個圖來描述一個page(頁面;4k)如何被這兩個結構體描述。
一個4k的頁面被分配到若剛個16 bytes大小的bucket中
一個4k的頁面被分配到若剛個32 bytes大小的bucket中。
那麼,這些資料結構是如何被初始化的呢?
首先,在核心代碼裡,寫入程式碼了如下資料。
struct _bucket_dir bucket_dir[] = {{ 16,(struct bucket_desc *) 0},{ 32,(struct bucket_desc *) 0},{ 64,(struct bucket_desc *) 0},{ 128,(struct bucket_desc *) 0},{ 256,(struct bucket_desc *) 0},{ 512,(struct bucket_desc *) 0},{ 1024,(struct bucket_desc *) 0},{ 2048, (struct bucket_desc *) 0},{ 4096, (struct bucket_desc *) 0},{ 0, (struct bucket_desc *) 0}}; /* End of list marker */
定義了粒度從16起的次方增長。
我寫了簡化的虛擬碼來描述整個流程。
malloc的虛擬碼:
procedure:get the bucket_desc with object size(for example 16 bytes)if(search bucket_desc list for free space){return bdesc->freeptr} else {if(init_bucket_desc){return bdesc->freeptr} else {panic("init_bucket_desc error")}}init_bucket_desc:if(page = get_one_page){sepreated the page(4k) with dir->sizelink all the pieces} else {panic("get page error")}end procedure
free的虛擬碼:
procedure:get the bucket_desc with object size(for example 16 bytes)if(search bucket_desc list for the related bucket_desc){erase bdesc->freeptrbdesc->refcnt--if(bdesc->refcnt == 0){if(whole page NULL){if(!free_page(bdesc->page)){panic("free_page error")}}}} else {panic("input pointer not right")}end procedure
關於資料結構效能的思考:
這裡的主要資料結構就是單向鏈表,尋找的時間複雜為O(N),屬於暴力尋找。
用了10個元素的數組做分拆,當記憶體使用量過大的時候,這個資料結構就不能承載了。
或許採用一個hash或者樹形結構能解決問題。
不過,對於20年前的記憶體來說,完全能應付了:)
lnux核心的malloc實現(Oracle的cache buffer影子)