写了一个简单的内存池; 主要用于需要不断的创建和销毁对象
已经重载了new/delete;
基本使用就3个接口
1. MemMgr::alloc 分配内存 (new 调用这个)
2.MemMgr::dealloc 释放 (delete调用这个)
3. MemMgr::createpool 创建内存池 ; 唯一需要额外调用的函数
基本思想就是在每个内存块前加一个MemBlock用于管理(用MemPool来管理),MemMgr来管理MemPool;
另外对于MemMgr来查询使用哪个pool 有多个方式,代码中给了2种方法;
我里面用map来管理pool , key用根据操作系统分配粒度的大小( sizeof(void*) ), 来找到最合适的pool,当然
前提是预先调用了createpool;
另外
1.下面的代码还没加锁, 需要用于多线程的可自行在 MemMgr 和 MemPool 中加锁;
2 . 还有对于MemBlock的管理方式并不是最好的一种, 只是给出一个思路, 可模拟目录对文件的管理方式;
1) MemBlock 每个申请的内存块都会附加这一头部
2) MemPool 可用于创建4字节, 8字节, 16字节.... 等等自定义的内存池. 最小的内存池还是以sizeof(void*)为单位 ,
通过指定内存块大小和数量来malloc 后初始化所有内存块的首部(MemBlock), 内部还有一个pUserBlock 来记录
哪些块已经使用;
3) MemMgr 用于管理MemPool , 查找并返回与字节数最匹配的内存池中的内存块, 当然还可以附加其他功能,
额外的功能自行发挥好了
// mem_mgr.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include <unordered_map>
#ifdef _DEBUG
#define PR(...) printf(__VA_ARGS__)
#else
#define PR(...)
#endif
#define BLOCK_SIZE_4 4
#define BLOCK_SIZE_8 8
#define BLOCK_SIZE_16 16
#define BLOCK_SIZE_32 32
#define BLOCK_SIZE_64 64
#define BLOCK_SIZE_128 128
#define BLOCK_SIZE_256 256
#define BLOCK_SIZE_512 512
#define BLOCK_SIZE_1024 1024
class MemPool;
class MemMgr;
//内存块描述信息,附着在每个可用内存块的头部
struct MemBlock
{
//index位置
int id;
//ref次数
unsigned int nref;
//属于哪个pool
MemPool * pool;
//下一个可使用地址 , 下面全部注释了, 这种方式不太好用
MemBlock * next;
};
static void * new_from_system(size_t size){
MemBlock *pRet = (MemBlock *)malloc(sizeof(MemBlock)+size);
if (!pRet)
return NULL;
pRet->id = -1;
pRet->next = 0;
pRet->nref = 1;
pRet->pool = 0;
return ((char*)pRet) + sizeof(MemBlock);
}
//内存池
class MemPool
{
//pool
char *pBuffer;
//可使用块单元,下面不再使用这个变量,用另一种查询方式
MemBlock *pAviliableBlock;
//MemBlock 大小
unsigned block_size;
//MemBlock 数量
unsigned block_count;
//内存块使用情况,用于查询
char * pBlockUsed;
private:
MemPool(const MemPool &);
MemPool & operator = (const MemPool &);
public:
MemPool(unsigned blockSize, unsigned blockCount) :
pBuffer(0), pAviliableBlock(0), block_size(blockSize), block_count(blockCount),
pBlockUsed(0){}
~MemPool(){
if (pBuffer){
free(pBuffer);
}
}
unsigned blockSize() const { return block_size; }
unsigned long long pool_size() const
{
return block_count * block_size;
}
int init(){
if (pBuffer)
return -1;
unsigned block_total_len = block_size + sizeof(MemBlock);
pBuffer = (char*)malloc(block_count * block_total_len);
if (!pBuffer)
return -1;
pBlockUsed = (char*)malloc(block_count);
if (!pBlockUsed)
return -1;
memset(pBlockUsed, 0, sizeof(char)*block_count);
pAviliableBlock = (MemBlock *)pBuffer;
MemBlock * p = NULL;
for (unsigned i = 0; i < block_count; ++i){
p = (MemBlock*)(pBuffer + i*block_total_len);
p->id = i;
//先写着
p->next = (MemBlock*)(pBuffer + (i+1)*block_total_len);
p->nref = 0;
p->pool = this;
}
p->next = NULL;
return 0;
}
void showEachBlock(){
unsigned block_total_len = block_size + sizeof(MemBlock);
for (unsigned i = 0; i < block_count; ++i){
MemBlock * p = (MemBlock*)(pBuffer + i * block_total_len);
printf("thisblock : %p , id:%d,nref:%d,next:%p \t", p, p->id, p->nref, p->next);
}
printf("\n");
}
void showUsedBlock(MemBlock * p = 0)
{
printf("\n *** alloc block blocksize : %ld , count:%ld ,pool:%p\t ", block_size, block_count, this);
for (unsigned i = 0; i < block_count; ++i)
printf("%d", pBlockUsed[i]);
printf("\n");
if (p){
printf("thisblock : %p , id:%d,nref:%d,next:%p \t", p, p->id, p->nref, p->next);
}
printf("****\n");
}
void * alloc(size_t size) {
if (!pBuffer)
return NULL;
MemBlock * pRet = NULL;
unsigned i = 0;
//找出可用内存块
for (i = 0; i < block_count && 1 == pBlockUsed[i]; ++i);
//超出内存池大小
if (i == block_count){
printf("pool is full index:%d\n", i);
return new_from_system(size);
}
else
{
pBlockUsed[i] = 1;
pRet = (MemBlock *)(pBuffer + i*(block_size + sizeof(MemBlock)));
pRet->nref = 1;
showUsedBlock(pRet);
}
/*if (!pAviliableBlock){
pRet = (MemBlock *)malloc(sizeof(MemBlock)+size);
if (!pRet)
return NULL;
pRet->id = -1;
pRet->next = 0;
pRet->nref = 1;
pRet->pool = 0;
}
else {
pRet = pAviliableBlock;
pAviliableBlock = pAviliableBlock->next;
pRet->nref = 1;
}*/
return ((char*)pRet) + sizeof(MemBlock);
}
void deAlloc(void * pMem){
if (!pMem){
printf("empty pointer! %s,%d\n", __FILE__, __LINE__);
return;
}
MemBlock * pMemBlock = (MemBlock*)((char*)pMem - sizeof(MemBlock));
if (!pMemBlock){
printf("can't dealloc pMemBlock , %s,%d\n", __FILE__, __LINE__);
return;
}
if (--pMemBlock->nref != 0){
printf("memblock nref:%d\n", pMemBlock->nref);
return;
}
if (pMemBlock->pool){
//这个情况在MemMgr中处理了, 不会发生
if (pMemBlock->pool != this){
printf("this block is not belong to this pool, this pool:%p, block_pool:%p %d \n",
this, pMemBlock->pool, __LINE__);
return;
}
/*
pMemBlock->next = pAviliableBlock;
pAviliableBlock = pMemBlock;
*/
pBlockUsed[pMemBlock->id] = 0;
showUsedBlock();
}
else{
free(pMemBlock);
}
}
};
//管理, 默认最多创建20个内存池
class MemMgr
{
public:
MemMgr(unsigned max_pool_count = 20) :_max_pool_count(max_pool_count),
pBuffer(NULL), _cur_pool_count(0)
{
pBuffer = (char*)malloc(max_pool_count * sizeof(MemPool));
}
~MemMgr(){
if (!pBuffer)
return;
MemPool * pStart = (MemPool *)pBuffer;
for (unsigned i = 0; i < _cur_pool_count; ++i, pStart++)
pStart->~MemPool();
free(pBuffer);
pBuffer = NULL;
}
static MemMgr& getInstance() {
return _instance;
}
//申请内存,选择某一个池中的内存块
//对于如何决定某个池中的内存块,有很多方式, 可自行决定如何去做
void * alloc(size_t size){
size_t blockSize = align_bytes(size);
if (blockSize < 1){
printf("blocksize error! %d\n", __LINE__);
return NULL;
}
//如果没有池就直接申请
if (_pool_map.empty()){
printf("_pool_map.empty! new from system %d \n", __LINE__);
return new_from_system(blockSize);
}
/*// 第一种方式, 以字节数为单位,作为key比如以4,8,16字节作为key, 找到对应的内存池
auto iter = _pool_map.find(blockSize);
if (iter == _pool_map.end()){
printf("no such pool! %d\n", __LINE__);
return new_from_system(blockSize);
}
else
return iter->second->alloc(blockSize);
*/
//第2中方式,找到内存池中能容纳size的最小尺寸的池,这种方式灵活一些
std::unordered_map<size_t, MemPool*>::iterator iter_find_min;
for (iter_find_min = _pool_map.begin(); iter_find_min != _pool_map.end(); ++iter_find_min){
if (size < iter_find_min->first)
break;
}
if (iter_find_min == _pool_map.end()){
printf("no such pool! new from system , pool size:%d , %d\n ",_pool_map.size(), __LINE__);
return new_from_system(blockSize);
}
return iter_find_min->second->alloc(blockSize);
}
/*
新建内存池,相同blocksize的池只能建立一个,你可自行改造一下成为多个池
以系统字节为边界 :sizeof(void*);
对于这个函数,即可以public,也可以private即自己预先分配好;
*/
int createPool(size_t blockSize = 8, size_t blockCount = 64)
{
if (!pBuffer){
printf("%d failed , buffer malloc failed!\n", __LINE__);
return -1;
}
if (_cur_pool_count >= _max_pool_count){
printf("%d , max pool !\n", __LINE__);
return -1;
}
if (blockSize < 1){
printf("blocksize error! %d\n", __LINE__);
return -1;
}
blockSize = align_bytes(blockSize);
//如果有相同尺寸的池,则不可新建
if (_pool_map.find(blockSize) != _pool_map.end()){
printf("key exists blocksize:%ld, %d\n", blockSize, __LINE__);
return -1;
}
MemPool * pool = new(pBuffer + sizeof(MemPool)*_cur_pool_count)MemPool(blockSize, blockCount);
if (pool->init() < 0){
printf("pool init failed! %d\n", __LINE__);
pool->~MemPool();
return -1;
}
std::pair<std::unordered_map<size_t, MemPool*>::iterator, bool> insert_pair;
insert_pair = _pool_map.insert(std::pair<size_t, MemPool*>(blockSize, pool));
if (!insert_pair.second){
printf("insert failed! %d\n", __LINE__);
return -1;
}
++_cur_pool_count;
return 0;
}
//释放
void deAlloc(void * pMem){
if (!pMem){
printf("empty pointer! %s,%d\n", __FILE__, __LINE__);
return;
}
//也可以 (MemBlock*)pMem -1;
MemBlock * pMemBlock = (MemBlock*)((char*)pMem - sizeof(MemBlock));
if (!pMemBlock){
printf("can't dealloc pMemBlock , %s,%d\n", __FILE__, __LINE__);
return;
}
//如果在池中,交给池去处理
if (pMemBlock->pool){
pMemBlock->pool->deAlloc(pMem);
}
else {
if (0 == --pMemBlock->nref){
free(pMemBlock);
}
}
}
void addRef(void * p){
MemBlock * pMemBlock = ((MemBlock*)p) - 1;
++pMemBlock->nref;
}
//补齐字节使用,让字节数能被系统整除
size_t align_bytes(size_t size){
size_t bytes = sizeof(void*);
return (size / bytes)*bytes + (size%bytes ? bytes : 0);
}
private:
MemMgr(const MemMgr&);
MemMgr & operator = (const MemMgr&);
static MemMgr _instance;
unsigned _max_pool_count;
unsigned _cur_pool_count;
char * pBuffer;
//第1,2种方式以补齐的字节数为单位作为key 的map
std::unordered_map<size_t, MemPool*> _pool_map;
};
MemMgr MemMgr::_instance;
void * operator new (size_t size){
return MemMgr::getInstance().alloc(size);
}
void operator delete(void * p){
return MemMgr::getInstance().deAlloc(p);
}
void * operator new[](size_t size){
return MemMgr::getInstance().alloc(size);
}
void operator delete[](void * p){
return MemMgr::getInstance().deAlloc(p);
}
int _tmain(int argc, _TCHAR* argv[])
{
MemMgr & instance = MemMgr::getInstance();
instance.createPool(4, 5);
/*char * p1 = new char;
printf("p1:%p\n", p1);
delete p1;
p1 = new char[127];
delete[] p1;*/
char * arr[10];
for (int i = 0; i < 10; ++i){
arr[i] = new char[2];
}
for (int i = 0; i < 10; ++i){
printf("arr[%d] = %p\t", i, arr[i]);
}
for (int i = 0; i < 10; ++i){
delete[] arr[i];
}
getchar();
return 0;
}