Arena是个很简单的内存池实现,因为leveldb应用总是一次性销毁掉整个内存,所以这里连delete都没有。在析构里都一起删了就行
class Arena {
public:
char* Allocate(size_t bytes);
......
private:
// 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_;
};
有4个成员变量。blocks_,每个元素为指向一个内存块的指针。这些块中只有唯一一个是当前未放满的块,alloc_ptr指向该块空闲区开始的部分,alloc_bytes_remining为该块还剩余的空闲长度。
当外部请求一块新内存时。简单的比较请求长度和alloc_bytes_remning,如果够用,返回当前alloc_ptr,修改alloc_ptr和reminging。如果不够用,调用AllocateFallback申请新块
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);
}
AllocateFallback的实现如下。如果请求长度够长,直接申请一个新块返回。新块只包含该请求用的内存。alloc_ptr和remaining依然指向原来的块。如果请求长度较短,alloc_ptr和remaining将调整到指向新块中未被分配的部分。注意,这里没有像一般内存池常见的那样,维护一个数据结构来索引各个老块中尚未使用的部分,而是直接废弃不用了。只能说适用于某些应用。
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;
}