Arena内存管理
简介
arena
这个单词在计算机领域中常表示一段连续的内存区域。
LevelDB
提供了 arena
这样的简单内存分配器来代替直接使用 malloc
分配一些小内存,其不支持释放内存,仅支持分配内存,内存释放的时机是在析构 arena
时发生,此时将会释放所有通过 arena
分配出来的内存。
所以 arena
适合内存不断增加,且会常驻内存不需要随时释放的场景。

内存分配如图,直接从固定大小的内存块中分配 size
大小的内存,返回其地址即可。使用 alloc_bytes_remaining_
变量来记录当前内存块还剩余多少字节, alloc_ptr_
遍历来记录在内存块中可以分配的起始地址。
如果当前块不够分配,arena
采用如下策略进行分配:
- 当前块足够分配,直接按上文所述分配即可。
- 当前块不足分配,且分配大小大于
1/4
块内存大小,生成分配所需大小的内存块,返回新内存块地址,下次分配使用未分配完的内存块。 - 当前块不足分配,且分配大小小于
1/4
块内存大小,生成新的内存块,分配使用新的内存块,老的内存块剩余内存不使用。
实现
构造函数
class Arena {
public:
Arena();
Arena(const Arena &) = delete;
Arena &operator=(const Arena &) = delete;
private:
// 如上图,alloc_ptr_ 表示当前可分配内存起始地址
// alloc_bytes_remaining_ 当前块剩余内存大小
char *alloc_ptr_;
size_t alloc_bytes_remaining_;
// 用来存放所有块的起始地址
std::vector<char *> blocks_;
// 内存使用率
std::atomic<size_t> memory_usage_;
}
// 构造函数默认直接使用初始值
Arena::Arena() : alloc_ptr_(nullptr), alloc_bytes_remaining_(0), memory_usage_(0) {
}
// 每一块的内存大小
static const int kBlockSize = 4096;
析构函数
// 析构时,把所有 new 出来的内存 delete 掉
// 注意使用 delete[],因为 new 的时候使用的是 new char[]
Arena::~Arena() {
for (size_t i = 0; i < blocks_.size(); i++) {
delete[] blocks_[i];
}
}