leveldb原始碼分析之記憶體池Arena

2022-08-17 23:00:15 字數 2719 閱讀 2940

**:

這篇部落格主要講解下leveldb記憶體池,記憶體池很多地方都有用到,像linux核心也有個記憶體池。記憶體池的存在主要就是減少malloc或者new呼叫的次數,較少記憶體分配所帶來的系統開銷。

arena類採用vector來儲存每次分配記憶體的指標,每一次分配的記憶體,我們稱為乙個塊block。block預設大小為4096kb。我們可以先看下arena的模型:

我們來看看原始碼: 首先看下這個類的幾個成員變數:12

34char* alloc_ptr_;//記憶體的偏移量指標,即指向未使用記憶體的首位址

size_t alloc_bytes_remaining_;//還剩下的記憶體數

std::vector blocks_;//儲存每一次分配的記憶體指標

size_t blocks_memory_;//到目前為止分配的總記憶體。

建構函式和析構函式:12

3456

78910

1112

arena::arena() //建構函式初始化總總分配的記憶體為0,指標偏移量為null,剩餘記憶體為0。

vector會呼叫預設建構函式初始化。

arena::~arena()

}//arena析構時,只需要把所有的指標指向的記憶體都delete就可以了。

都說谷歌的c++程式設計風格是最優美的。leveldb裡面的每個類的建構函式都直接初始化所有的屬性,這樣就不會導致使用為初始化的變數,而且**很清晰,知道哪些屬性被初始化為何值。

接下來分析下arena記憶體分配的主要函式。12

345public:

char* allocate(size_t bytes);

private:

char* allocatefallback(size_t bytes);

char* allocatenewblock(size_t block_bytes);

arena對外提供的介面是public裡的函式,但是該函式會呼叫private裡的兩個函式.我分析記憶體分配策略。當要分配記憶體的時候:

如果需求的記憶體小於剩餘的記憶體,那麼直接在剩餘的記憶體分配就可以了;

如果需求的記憶體大於剩餘的記憶體,而且大於4096/4,則給這記憶體單獨分配一塊bytes(函式引數)大小的記憶體。

如果需求的記憶體大於剩餘的記憶體,而且小於4096/4,則重新分配乙個記憶體塊,預設大小4096,用於儲存資料。

針對第二點,按原始碼的注釋是說避浪費太多的剩餘空間。我的理解是,如果剩餘的記憶體為1500kb,那麼假設有乙個記憶體需求是500kb,乙個記憶體需求是1500kb,則第乙個需求可以使用三次才導致進行一次重新記憶體分配,而第二個只能使用一次就要進行一次重新記憶體分配。所以leveldb第二條的用意主要還是減少記憶體分配的次數。

原始碼如下:12

3456

78910

1112

1314

1516

1718

1920

2122

2324

2526

2728

2930

3132

3334

3536

3738

39inline char* arena::allocate(size_t bytes)

return allocatefallback(bytes);//當需求記憶體大於剩餘記憶體時

}char* arena::allocatefallback(size_t bytes)

// we waste the remaining space in the current block.

alloc_ptr_ = allocatenewblock(kblocksize);//需求記憶體大於剩餘記憶體,且小於1024時。

alloc_bytes_remaining_ = kblocksize;

char* result = alloc_ptr_;

alloc_ptr_ += bytes;

alloc_bytes_remaining_ -= bytes;

return result;

}char* arena::allocatenewblock(size_t block_bytes)

arena還提供了位元組對齊記憶體分配,一般情況是8個位元組對齊分配,即記憶體位址後三位必須為0.我們來看下原始碼,挺多學問的。12

3456

78910

1112

1314

1516

1718

1920

2122

23char* arena::allocatealigned(size_t bytes) else

assert((reinterpret_cast(result) & (align-1)) == 0);

return result;

}這裡邊有乙個uintptr_t型別,定義在標頭檔案裡,是無符號長整形型別,是typedef unsigned long int 型別,對應有符號型別為typedef long int intptr_t。這種型別是機器指標大小對應,如果32位系統,則uintptr_t也為32位,如果是64位系統,則這個值為64位。

arena最後乙個對外介面是返回這個記憶體池分配總的記憶體大小。12

3size_t memoryusage() const

arena記憶體大小包括分配的記憶體空間大小和所有指標大小之和。

arena在memtabla(也就是跳躍鍊錶)使用較多,因為剛插入的記憶體資料都放在了memtable裡。

至此arena就分析結束了。

leveldb原始碼分析 記憶體池 Arena

模組資訊 util arena.h util arena.cc 模組概要 用於實現乙個簡單的記憶體池,有兩種記憶體分配方式,一種是普通分配,一種是對齊分配 主要介面 方法說明 char arena allocate size t bytes 普通方式分配記憶體 char arena allocate...

leveldb原始碼分析1

leveldb是乙個key value型的儲存引擎,由google開發,並宣布在bsd許可下開放源 plain git clone plain cd leveldb make all 此時生成libleveldb.a庫檔案。拷貝leveldb的標頭檔案到 usr include下 plain cp ...

levelDB原始碼分析 SSTable

sstable是bigtable中至關重要的一塊,對於leveldb來說也是如此,對leveldb的sstable實現細節的了解也有助於了解bigtable中一些實現細節。本節內容主要講述sstable的靜態布局結構,sstable檔案形成了不同level的層級結構,至於這個層級結構是如何形成的我們...