ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【LevelDB源码阅读】Arena

2020-06-09 09:06:07  阅读:332  来源: 互联网

标签:Arena LevelDB bytes char 源码 内存 memory size


是什么

内存分配管理器,主要为skiplist即Memtable服务而不是整个项目。申请内存时,将申请到的内存直接放入vector中,在Arena的生命周期结束后,统一释放掉所有申请的内存,内部结构如下图:

为什么要用

  • 避免内存碎片,skiplist里面记录的都是用户传进来的key/value,这些字符串有长有短,放到内存中很容易导致内存碎片

学到什么

  • 与(&)操作进行内存对齐
  • atomic保证原子性
  • 使用delete避免拷贝和赋值操作

源码分析

首先看一下内部成员

  // Allocation state
  char *alloc_ptr_;  // 内存偏移量指针,指向未使用内存的首地址
  size_t alloc_bytes_remaining_;  // 剩下内存数

  // Array of new[] allocated memory blocks
  std::vector<char*> blocks_;  // 存储每次分配的内存指针

  // Total memory usage of the arena.
  //
  // TODO(costan): This member is accessed via atomics, but the others are
  //               accessed without any locking. Is this OK?
  std::atomic<size_t> memory_usage_;

构造函数和析构函数

Arena::Arena()  // vector调用默认构造函数初始化
    : alloc_ptr_(nullptr), alloc_bytes_remaining_(0), memory_usage_(0) {}

Arena::~Arena() {
  for (size_t i = 0; i < blocks_.size(); i++) {
    delete[] blocks_[i];
  }
}

拷贝构造和拷贝赋值

  Arena(const Arena&) = delete;
  Arena& operator=(const Arena&) = delete;

主要对外接口

  // Return a pointer to a newly allocated memory block of "bytes" bytes.
  char* Allocate(size_t bytes);

  // Allocate memory with the normal alignment guarantees provided by malloc.
  char* AllocateAligned(size_t bytes);

具体实现如下:

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()分配内存:

  • 如果需要内存大于4096/4,则直接分配一块大小为bytes内存,避免每次剩余内存不可用,造成浪费。
  • 否则,重新分配一个内存块(默认大小4096)用于存储数据,虽然浪费了当前内存块的剩余内存,但当下次再分配小内存时,可以直接使用,减少内存分配次数。

具体实现如下:

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;
}

其中分配新内存块实现如下:
memory_order_relaxed:针对只要求原子操作,除此之外不需要其它同步保证,计数器是一种典型应用场景。

char* Arena::AllocateNewBlock(size_t block_bytes) {
  char *result = new char[block_bytes];
  blocks_.push_back(result);  // 申请块放入vector,以便析构函数释放内存
  memory_usage_.fetch_add(block_bytes + sizeof(char*),
                          std::memory_order_relaxed);
  return result;
}

对齐内存分配

char* Arena::AllocateAligned(size_t bytes) {
  const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8;  // 与系统相关,4或8
  static_assert((align & (align - 1)) == 0,
                "Pointer size should be a power of 2");  // 确保是2的指数次方
  size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align - 1);  // 当前指针模对齐值
  size_t slop = (current_mod == 0 ? 0 : align - current_mod);  // 还差slop个字节对齐
  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;
}

读取内存使用

  // Returns an estimate of the total memory usage of data allocated
  // by the arena.
  size_t MemoryUsage() const {
    return memory_usage_.load(std::memory_order_relaxed);
  }

标签:Arena,LevelDB,bytes,char,源码,内存,memory,size
来源: https://www.cnblogs.com/galaxy-hao/p/13070332.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有