Linux核心的malloc實現(Oracle的cache buffer影子)
阿新 • • 發佈:2019-02-20
本文介紹一下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, (structbucket_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年前的記憶體來說,完全能應付了:)