Arena类
Arena类是极为简易的内存池实现,支持动态申请内存空间(内存对齐/不对齐方式),通过RAII机制保证Arena对象管理的内存在Arena对象生命周期结束后自动清理。
源文件位置
util/arena.h
util/arena.cc
优点:访问速度快
缺点:存在内存浪费,详细见下文AllocateFallback接口分析;不支持Deallocate操作,不适合作为常驻内存池使用;不当的访问Allocate/AllocateAligned申请的内存将导致预期外的错误
公共接口
char* Allocate(size_t bytes); // 从Arena中申请指定大小的内存块 char* AllocateAligned(size_t bytes); // 从Arena中申请指定大小的内存块(内存对齐) size_t MemoryUsage() const // 获取内存使用率;
私有接口
char* AllocateFallback(size_t bytes); // 在Arena剩余的已申请的内存空间不足时用于申请新的内存块 char* AllocateNewBlock(size_t block_bytes); // 调用new申请block_bytes大小的内存并更新blocks_及memory_usage_
私有成员变量
char* alloc_ptr_; // 当前block内空闲内存的起始地址 size_t alloc_bytes_remaining_; // 当前block内空闲内存大小 std::vector<char*> blocks_; // 申请的所有内存块,由vecotr进行管理 std::atomic<size_t> memory_usage_; // Arena内存使用率
构造函数/析构函数
Arena(); // 初始化各成员变量,初始的Arena是空的,并不像常见的内存池实现中会预申请指定大小的内存块 ~Arena(); // 释放所有申请的内存块
关键接口
char* AllocateFallback(size_t bytes);
实现思想:
申请的内存超出4096字节时,直接分配新的block给使用者,不改变alloc_ptr_及alloc_bytes_remaining指向,避免浪费内存
申请的内存低于1024字节时,将申请新的4096字节大小的block,此时将会放弃原block中剩余的内存(因为alloc_ptr以及alloc_bytes_remaining将会指向新的block)
源码(注释版):
char* Arena::AllocateFallback(size_t bytes) { // 若bytes大于1024字节时,恰好申请bytes字节大小的block并将此block作为结果返回 // 此时Arena的alloc_ptr_及alloc_bytes_remaining_仍指向的具有剩余空间的block,从而避免内存浪费 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; } // 直接申请4096字节大小的block,此时将会放弃原block中剩余的内存(因为alloc_ptr_以及alloc_bytes_remaining_将会指向新的block) // We waste the remaining space in the current block. alloc_ptr_ = AllocateNewBlock(kBlockSize); alloc_bytes_remaining_ = kBlockSize; // 从新的block中分配bytes大小的空间 char* result = alloc_ptr_; alloc_ptr_ += bytes; alloc_bytes_remaining_ -= bytes; return result; }char* AllocateAligned(size_t bytes); 实现思想: 以内存对齐的方式申请内存,除去计算内存对齐需补齐的slop外逻辑与Allocate等同 源码(注释版):
char* Arena::AllocateAligned(size_t bytes) { // 获取环境上应以多少位进行字节对齐(最低为8字节对齐) const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8; // 指针大小必须为2的幂,以8字节对齐为例(即align为8),1000 & 0111结果为0 // 若align非2的幂值,由于align、align - 1的最高位非0的最高位必然相同,因此两者结果必定不为0,(以align为9为例),1001 & 1000结果为8 static_assert((align & (align - 1)) == 0, "Pointer size should be a power of 2"); // 计算当前alloc_ptr_指向的地址若按align对齐,有多少字节是不满足对齐要求的,类似reinterpret_cast<uintptr_t>(alloc_ptr_) % align // 因此为了字节对齐,需要额外补充align - current_mod字节 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; // 若剩余的已申请的内存空间可满足要求,则直接在已申请的内存上分配 if (needed <= alloc_bytes_remaining_) { result = alloc_ptr_ + slop; alloc_ptr_ += needed; alloc_bytes_remaining_ -= needed; } else { // 剩余的已申请的内存空间不满足要求,则新申请内存块 // AllocateFallback always returned aligned memory result = AllocateFallback(bytes); } // 保证由上述计算后申请的内存起始地址必然是内存对齐的 assert((reinterpret_cast<uintptr_t>(result) & (align - 1)) == 0); return result; }
标签:Arena,alloc,LevelDB,utils,bytes,内存,block,size From: https://www.cnblogs.com/pond-flower/p/17900043.html