概述
定义内存管理的相关行为。使用了预分配的管理,先分配一块足够大的内存,然后需要时再从这块内存中进行分配。
代码仓库: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;
}