现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

leveldb学习:内存池Arena

2020-01-10 06:46 工业·编程 ⁄ 共 2116字 ⁄ 字号 暂无评论

和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*) > 8) ? sizeof(void*) : 8;

  //验证一个数是2的指数的奇巧淫技

  assert((align & (align-1)) == 0);   // Pointer size should be a power of 2

  //内存对齐的奇巧淫技

  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;

  //当前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-1)) == 0);

  return result;

}

leveldb向内存申请一块空间的请求交由arena实现,就会调用AllocateAligned函数,分配时要求内存对齐。

当现有的block剩余空间不足时,需要重新申请

block(AllocateFallback)

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;

}

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_大小的浪费。

给我留言

留言无头像?