1. 程式人生 > >Linux核心的malloc實現(Oracle的cache buffer影子)

Linux核心的malloc實現(Oracle的cache buffer影子)

本文介紹一下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 */ int size; struct bucket_desc *chain; };

我畫了兩個圖來描述一個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->size
link 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->freeptr
bdesc->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

關於資料結構效能的思考:

       這裡的主要資料結構就是單向連結串列,用了10個元素的陣列做分拆,當記憶體使用過大的時候,這個資料結構就不能承載了。

       對於20年前的記憶體來說,完全能應付了:)