leveldb學習:記憶體池Arena
阿新 • • 發佈:2018-12-31
和SGI版的STL一樣,leveldb記憶體分配也採用了memory pool的整理方式,減少記憶體不斷分配釋放過程中造成的空間零碎化和浪費。leveldb的記憶體池實現可參見arena.h和arena.cc,有關記憶體池的測試程式碼有arena_test.cc。arena記憶體池是leveldb的關鍵元件,是很多其他功能模組(class)的成員,在cache、memtable、table元件中均有使用。
先看arena的成員變數:
private:
// Allocation state
//當前記憶體池的池頂
char* alloc_ptr_;
// 當前block還剩的可分配空間
size_t alloc_bytes_remaining_;
// Array of new[] allocated memory blocks
//每塊block地址
std::vector<char*> blocks_;
// Bytes of memory in blocks allocated so far
//記憶體池大小
size_t blocks_memory_;
再看介面:
arena是按block管理記憶體的,當上層的元件向記憶體申請記憶體時,底層的arena將指定早已分配好的block返回給上層,當block剩餘的空間不足一次申請所需的空間時,arena重新申請一個block。
char* Arena::AllocateAligned(size_t bytes) {
//將對齊的值設為指標大小和8的小者
const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8;
//驗證一個數是2的指數的奇巧淫技
assert((align & (align-1)) == 0); // Pointer size should be a power of 2
//記憶體對齊的奇巧淫技
size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align-1 );
size_t slop = (current_mod == 0 ? 0 : align - current_mod);
size_t needed = bytes + slop;
char* result;
//當前block剩餘空間足夠,直接分配,並更新alloc_bytes_remaining_
if (needed <= alloc_bytes_remaining_) {
result = alloc_ptr_ + slop;
alloc_ptr_ += needed;
alloc_bytes_remaining_ -= needed;
} else {
// AllocateFallback always returned aligned memory
//剩餘空間不足,重新分配block
result = AllocateFallback(bytes);
}
assert((reinterpret_cast<uintptr_t>(result) & (align-1)) == 0);
return result;
}
leveldb向記憶體申請一塊空間的請求交由arena實現,就會呼叫AllocateAligned函式,分配時要求記憶體對齊。
當現有的block剩餘空間不足時,需要重新申請
block(AllocateFallback)
char* Arena::AllocateFallback(size_t bytes) {
if (bytes > kBlockSize / 4) {
// Object is more than a quarter of our block size. Allocate it separately
// to avoid wasting too much space in leftover bytes.
char* result = AllocateNewBlock(bytes);
return result;
}
// We waste the remaining space in the current block.
alloc_ptr_ = AllocateNewBlock(kBlockSize);
alloc_bytes_remaining_ = kBlockSize;
char* result = alloc_ptr_;
alloc_ptr_ += bytes;
alloc_bytes_remaining_ -= bytes;
return result;
}
kBlockSize=4096,如果申請的大小大於kBlockSize/4,則將申請一個bytes大小的block,否則,申請一個kBlockSize大小的block,bytes只佔block的一部分,剩下的空間交由後面使用。
arena解構函式會把容器block_中指向blocks空間的指標依次delete。也就是釋放了記憶體空間。
缺點:arena在申請的空間大於當前block所剩空間時(needed >= alloc_bytes_remaining_),側拋棄當前block,重新申請新的一塊block,這樣就會造成老block的alloc_bytes_remaining_大小的浪費。