符合Misra C++标准且支持mmap的内存池管理模块

发布于:2024-05-13 ⋅ 阅读:(184) ⋅ 点赞:(0)

概述

定义内存管理的相关行为。使用了预分配的管理,先分配一块足够大的内存,然后需要时再从这块内存中进行分配。
代码仓库:https://gitee.com/liudegui/mem_pool

类之间的关系

模块名 功能
MemPool 内存池模块入口,提供常用的模块间交互需要的数据内存池管理
MemAllocDelegate 用于内存池中的统一对整块系统内存的申请和释放,有Mem和Default两种申请方式
MemPoolManager 对由MemMapMemAllocator申请到的整块大内存,进行小颗粒度的精准分配和释放(这里的申请和释放不是针对系统资源,而是针对内存池中的大块内存而言)
DefaultMemAllocator 默认的内存申请方式。使用是std::list<std::vector<int8_t>>申请和管理。
MemMapMemAllocator 内存映射方式申请共享内存

MemPool 使用 MemPoolDelegate 来获取一块大的内存,然后使用 MemPoolManager 对这块内存进行关系。
在这里插入图片描述
1、DefaultMemAllocator模块使用C++的STL的std::list<std::vector<int8_t>>申请内存;
原因:符合Misra规范,Misra C和C++都不支持直接使用malloc/new申请内存
2、MemAllocDelegate支持两种内存申请方式的对象,DefaultMemAllocator和MemMapMemAllocator;
3、/dev/mem: /dev/mem是系统物理内存的映像文件;
/dev/zero: 在类UNIX 操作系统中, /dev/zero 是一个特殊的文件,当你读它的时候,它会提供无限的空字符(NULL, ASCII NUL, 0x00)。

关键过程

MemPool 创建

  • 首先分配一块的内存,内存大小:unit_count_ + 1*unit_size_ bytes;
  • 然后按照 alignment 进行对齐;
  • 最后创建MemPoolManager manager_ ,在MemPoolManager中,会将创建并初始化空闲位图 in_use_ 和空闲链表next_free_,具体见代码:
MemPoolManager::MemPoolManager(const char *name, void *buffer, unsigned int unit_size, unsigned int unit_count) {
  name_ = strdup(name);
  pool_ = buffer;
  unit_size_ = unit_size;
  unit_count_ = unit_count;
  free_count_ = unit_count_;
  // 创建 use map 和 free list
  in_use_ = reinterpret_cast<bool *>(malloc(unit_count * sizeof(bool)));
  next_free_ = reinterpret_cast<int *>(malloc(unit_count * sizeof(int)));
  // 初始化 use map 和 free list
  for (unsigned int i = 0; i < unit_count; i++) {
    in_use_[i] = false;
    next_free_[i] = i + 1;
  }
  first_free_ = 0;
  last_free_ = unit_count_ - 1;
  next_free_[last_free_] = -1;
}

MemPool alloc

  • 判断请求 size 是否大于 unit_size,若大于则返回 NULL;
  • 判断是否有空闲的 unit, 若没有则返回 NULL;
  • 从 free list 中取出第一个 free unit, 将其标记为 used, 并从 free list 中移除

具体见如下代码:

void *MemPoolManager::alloc(unsigned int size) {
  void *ret = NULL;
  std::unique_lock<std::mutex> lck(mutex_);
  alloc_call_count_++;
  if (size > unit_size_) {
    // 请求的内存大小超过了 unit_size
    request_too_big_++;
    return_null_count_++;
    lck.unlock();
    return NULL;
  }
  if (free_count_ <= 0) {
    // 没有空闲的 unit
    return_null_count_++;
    ret = NULL;
  } else {
    // 从 free list 中取出第一个 free unit, 将其标记为 used, 并从 free list 中移除
    int f = first_free_;
    first_free_ = next_free_[f];
    next_free_[f] = -1;
    if (last_free_ == f) {
      last_free_ = -1;
    }
    in_use_[f] = true;
    // 计算该 free unit 的起始地址
    ret = reinterpret_cast<char *>(pool_) + unit_size_ * f;
    free_count_--;
  }
  return ret;
}

MemPool free

  • 计算要释放的 buffer 在 pool 中的 unit index;
  • 将该 unit 标记为 free, 并加入 free list
void MemPoolManager::free(void *buffer) {
  std::unique_lock<std::mutex> lck(mutex_);
  // 计算 buffer 在 pool 中的 unit index
  uint64_t offset = reinterpret_cast<char *>(buffer) - reinterpret_cast<char *>(pool_);
  unsigned int idx = offset / unit_size_;
  unsigned int mod = offset % unit_size_;
  // 将该 unit 标记为 free, 并加入 free list
  in_use_[idx] = false;
  int l = last_free_;
  if (l == -1) {
    last_free_ = idx;
    first_free_ = idx;
  } else {
    next_free_[l] = idx;
    last_free_ = idx;
  }
  free_count_++;
  return;
}

网站公告

今日签到

点亮在社区的每一天
去签到