和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*) > ) ? sizeof(void*) : ;
//驗證一個數是2的指數的奇巧淫技
assert((align & (align-)) == ); // Pointer size should be a power of 2
//記憶體對齊的奇巧淫技
size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align-);
size_t slop = (current_mod == ? : 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-)) == );
return result;
}
leveldb向記憶體申請一塊空間的請求交由arena實作,就會調用AllocateAligned函數,配置設定時要求記憶體對齊。
當現有的block剩餘空間不足時,需要重新申請
block(AllocateFallback)
char* Arena::AllocateFallback(size_t bytes) {
if (bytes > kBlockSize / ) {
// 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_大小的浪費。