内存池设计与实现
alloctor.h
#ifndef _ALLOCTOR_H_
#define _ALLOCTOR_H_
void* operator new(size_t size);
void operator delete(void* p);
void* operator new[](size_t size);
void operator delete[](void* p);
void* mem_alloc(size_t size);
void mem_free(void* p);
#endif // !_ALLOCTOR_H_
alloctor.cpp
#include "alloctor.h"
#include "memory_manage.h"
void* operator new(size_t size){
return MemoryManage::get_instance().mm_alloc_memory(size);
}
void operator delete(void* p) {
MemoryManage::get_instance().mm_free_memory(p);
}
void* operator new[](size_t size) {
return MemoryManage::get_instance().mm_alloc_memory(size);
}
void operator delete[](void* p) {
MemoryManage::get_instance().mm_free_memory(p);
}
void* mem_alloc(size_t size) {
return MemoryManage::get_instance().mm_alloc_memory(size);
}
void mem_free(void* p) {
MemoryManage::get_instance().mm_free_memory(p);
}
memory_pool.h
#ifndef _MEMORY_MANAGE_H_
#define _MEMORY_MANAGE_H_
#include <stdlib.h>
#include <mutex>
/*
#ifdef _DEBUG
#include <stdio.h>
#include <assert.h>
#define xPrintf(...) printf(__VA_ARGS__)
#else
#define xPrintf(...)
#endif // _DEBUG
*/
const int MAX_MEMORY_SIZE = 128;
class MemoryAlloc;
// 描述单个内存块的信息 x64 : 32字节
class MemoryBlock {
public:
MemoryAlloc* _alloc; // 所属的内存池
MemoryBlock* _next; // 下一块位置
int _nId; // 内存块编号
int _nRef; // 引用次数
bool _inpool; // 释放在内存池中
private:
//下面三个是为了内存对齐
char c1;
char c2;
char c3;
};
// 内存池
class MemoryAlloc {
public:
MemoryAlloc() :
_cell_header(nullptr),
_memory_pool_addr(nullptr),
_block_size(0),
_block_num(0) {}
~MemoryAlloc() {
if (_memory_pool_addr) {
free(_memory_pool_addr);
}
}
public:
// 初始化
void init_memory_pool();
// 申请内存
void* ma_alloc_memory(size_t size);
// 释放内存
void ma_free_memory(void* memory);
protected:
MemoryBlock* _cell_header; // 内存池第一个内存块
char* _memory_pool_addr; // 内存池起始地址
size_t _block_size; // 内存单元大小
size_t _block_num; // 内存单元数量
std::mutex _mutex; // 锁
};
// 便于在声明类成员变量时初始化MemoryAlloc的成员数据
template<size_t block_size, size_t block_num>
class MemoryAlloctor : public MemoryAlloc {
public:
MemoryAlloctor() {
// xPrintf("MemoryAlloctor\n");
// 为了防止传入的nSize不是整数倍,这样的话会造成内存碎片,因此我们使用运算,如果传入的数值不是整数倍,那么就转换为整数倍
const size_t n = sizeof(void*);
_block_size = (block_size / n) * n + (block_size % n ? n : 0);
_block_num = block_num;
}
};
// 内存管理工具
class MemoryManage {
private:
MemoryManage() {
init_memory_array(0, 64, &_memory_size_64);
init_memory_array(65, 128, &_memory_size_128);
/*init_memory_array(129, 256, &_memory_size_256);
init_memory_array(257, 512, &_memory_size_512);
init_memory_array(513, 1024, &_memory_size_1024);*/
// xPrintf("MemoryManage\n");
}
~MemoryManage() {}
public:
// 返回内存管理的引用
static MemoryManage& get_instance();
// 申请内存
void* mm_alloc_memory(size_t size);
// 释放内存
void mm_free_memory(void* memory);
// 增加内存块的引用计数
void add_ref(void* memory);
private:
// 初始化内存池映射数组
void init_memory_array(int nbegin, int nend, MemoryAlloc* memory);
private:
MemoryAlloctor<64, 4000000> _memory_size_64; //内存池,该内存池有100块单个内存块,每个内存块64KB(下同)
MemoryAlloctor<128, 2000000> _memory_size_128;
/*MemoryAlloctor<256, 100000> _memory_size_256;
MemoryAlloctor<512, 100000> _memory_size_512;
MemoryAlloctor<1024, 100000> _memory_size_1024;*/
MemoryAlloc* _memory_array[MAX_MEMORY_SIZE + 1]; //数组用来存储上面的那些内存池
};
#endif // !_MEMORY_MANAGE_H_
memory_pool.cpp
#include "memory_manage.h"
// 初始化
void MemoryAlloc::init_memory_pool() {
// 断言
// assert(_memory_pool_addr == nullptr);
// 如果不为空,说明已经初始化过了,直接return
if (_memory_pool_addr) { return; }
// 计算单个内存块的大小
size_t single_cell_size = _block_size + sizeof(MemoryBlock);
// 计算内存池总大小
size_t total_pool_size = single_cell_size * _block_num;
// 向系统申请池的内存
_memory_pool_addr = (char*)malloc(total_pool_size);
// 初始化内存池
// 初始化第一块内存
_cell_header = (MemoryBlock*)_memory_pool_addr;
_cell_header->_inpool = true;
_cell_header->_nId = 0;
_cell_header->_nRef = 0;
_cell_header->_alloc = this;
_cell_header->_next = nullptr;
// 初始化剩余块的内容
MemoryBlock* temp_next = _cell_header;
for (size_t n = 1; n < _block_num; ++n) {
MemoryBlock* temp = (MemoryBlock*)(_memory_pool_addr + (n * single_cell_size));
temp->_inpool = true;
temp->_nId = n;
temp->_nRef = 0;
temp->_alloc = this;
temp->_next = nullptr;
temp_next->_next = temp;
temp_next = temp;
}
}
// 申请内存
void* MemoryAlloc::ma_alloc_memory(size_t size) {
//加锁
std::lock_guard<std::mutex> lock(_mutex);
// 如果内存池未初始化,那么进行初始化
if (!_memory_pool_addr) { init_memory_pool(); }
MemoryBlock* memory_retrun = nullptr;
/*如果内存池使用完了,那么_pHeader应该指向某个内存块的最后nullptr尾指针
此时调用malloc向系统申请内存,不向我们的内存池进行内存申请*/
if (nullptr == _cell_header) {
memory_retrun = (MemoryBlock*)malloc(_block_size + sizeof(MemoryBlock));
memory_retrun->_inpool = false;
memory_retrun->_nId = -1;
memory_retrun->_nRef = 1;
// 这个不属于内存处管理,所以设置为nullptr
memory_retrun->_alloc = nullptr;
memory_retrun->_next = nullptr;
printf("ma_alloc_memory: %llx, id=%d, size=%d\n", memory_retrun, memory_retrun->_nId, size);
} else {
//申请的时候将_pHeader向后移动
memory_retrun = _cell_header;
_cell_header = _cell_header->_next;
// assert(0 == memory_retrun->_nRef);
memory_retrun->_nRef = 1;
}
// xPrintf("ma_alloc_memory: %llx, id=%d, size=%d\n", memory_retrun, memory_retrun->_nId, size);
return (char*)memory_retrun + sizeof(MemoryBlock);
}
// 释放内存
void MemoryAlloc::ma_free_memory(void* memory) {
// 参数传入的是实际可用的内存地址,需要减去sizeof(MemoryBlock)才能得到整个单个内存块的内容
MemoryBlock* memory_block = (MemoryBlock*)((char*)memory - sizeof(MemoryBlock));
// assert(1 == memory_block->_nRef);
// 如果申请的内存属于内存池中的,不是系统申请的,则执行if
if (memory_block->_inpool) {
// 加锁
std::lock_guard<std::mutex> lock(_mutex);
// 先将该内存块的引用计数减1,然后判断引用计数是否大于1,如果大于1那么不释放直接return
if (--memory_block->_nRef != 0) { return; }
// 释放内存的时候将_pHeader前移,与申请时相反
memory_block->_next = _cell_header;
_cell_header = memory_block;
} else {
if (--memory_block->_nRef != 0) { return; }
free(memory_block);
}
}
// 返回内存管理的引用
MemoryManage& MemoryManage::get_instance() {
// 单例模式 静态
static MemoryManage memory_manage;
return memory_manage;
}
// 申请内存
void* MemoryManage::mm_alloc_memory(size_t size) {
if (size <= MAX_MEMORY_SIZE) {
return _memory_array[size]->ma_alloc_memory(size);
}
else {
MemoryBlock* memory_retrun = (MemoryBlock*)malloc(size + sizeof(MemoryBlock));
memory_retrun->_inpool = false;
memory_retrun->_nId = -1;
memory_retrun->_nRef = 1;
// 这个不属于内存处管理,所以设置为nullptr
memory_retrun->_alloc = nullptr;
memory_retrun->_next = nullptr;
// xPrintf("mm_alloc_memory: %llx, id=%d, size=%d\n", memory_retrun, memory_retrun->_nId, size);
return (char*)memory_retrun + sizeof(MemoryBlock);
}
}
// 释放内存
void MemoryManage::mm_free_memory(void* memory) {
MemoryBlock* memory_block = (MemoryBlock*)((char*)memory - sizeof(MemoryBlock));
// xPrintf("mm_alloc_memory: %llx, id=%d\n", memory_block, memory_block->_nId);
if (memory_block->_inpool) {
memory_block->_alloc->ma_free_memory(memory);
} else {
if (--memory_block->_nRef == 0) {
free(memory_block);
}
}
}
// 增加内存块的引用计数
void MemoryManage::add_ref(void* memory) {
MemoryBlock* memory_block = (MemoryBlock*)((char*)memory - sizeof(MemoryBlock));
++memory_block->_nRef;
}
// 初始化内存池映射数组
void MemoryManage::init_memory_array(int nbegin, int nend, MemoryAlloc* memory) {
for (int n = nbegin; n <= nend; n++) {
_memory_array[n] = memory;
}
}