本文介紹arena記憶體管理的設計和實作。
arena是leveldb中一個非常簡單的記憶體池,以下做詳細介紹。
1 資料結構
arena資料結構如下,其中,blocks_儲存着所有建立的block;blocks_memory_儲存所有block申請的總空間;alloc_ptr_和alloc_bytes_remaining_分别是目前block的記憶體配置設定起始位址 和 可用空間大小。
// Allocation state
char* alloc_ptr_;
size_t alloc_bytes_remaining_;
// Array of new[] allocated memory blocks
std::vector<char*> blocks_;
// Bytes of memory in blocks allocated so far
size_t blocks_memory_;
2 配置設定記憶體
inline char* Arena::Allocate(size_t bytes) {
// The semantics of what to return are a bit messy if we allow
// 0-byte allocations, so we disallow them here (we don't need
// them for our internal use).
assert(bytes > 0);
if (bytes <= alloc_bytes_remaining_) {
char* result = alloc_ptr_;
alloc_ptr_ += bytes;
alloc_bytes_remaining_ -= bytes;
return result;
}
return AllocateFallback(bytes);
}
// Allocate memory with the normal alignment guarantees provided by malloc
char* AllocateAligned(size_t bytes);
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;
}
char* Arena::AllocateNewBlock(size_t block_bytes) {
char* result = new char[block_bytes];
blocks_memory_ += block_bytes;
blocks_.push_back(result);
return result;
}
記憶體配置設定由Allocate方法完成,可以使用AllocateAligned獲得一個大小對齊的記憶體。Allocate方法首先根據alloc_bytes_remaining_判斷目前block剩餘空間是否足夠,足夠則直接在目前block申請。不足時,判斷所需空間的大小,如果大于1/4的blocksize,就當做一個單獨的block進行申請;小于等于1/4的blocksize時,申請一個新的block,從新的block中配置設定記憶體。因為當單獨作為一個block進行申請的時候,alloc_ptr_和alloc_bytes_remaining_指向的block并沒有改變,也就是目前block剩餘空間仍然可用,是以這樣做可以減少記憶體浪費,對于每個block,最多不超過1/4的blocksize的記憶體會被浪費掉。這個blocksize設定為4096。
3 釋放記憶體
Arena::Arena() {
blocks_memory_ = 0;
alloc_ptr_ = NULL; // First allocation will allocate a block
alloc_bytes_remaining_ = 0;
}
Arena::~Arena() {
for (size_t i = 0; i < blocks_.size(); i++) {
delete[] blocks_[i];
}
}
記憶體隻有在arena對象被銷毀的時候,才能統一釋放。是以Arena記憶體隻能增長。