Author:阿冬哥
Created:2013-4-18
Blog:http://blog.csdn.net/c359719435/
Copyright 2013 阿冬哥 http://blog.csdn.net/c359719435/
使用以及转载请注明出处
1 内存池
内存池是一种内存分配方式。一般我们习惯用new\malloc在需要使用内存时分配内存,这样做的缺点是:调用new、malloc有一定的开销,由于每次调用的大小不确定所以频繁的调用会产生内存碎片从而降低性能。内存池则是在使用内存之前,预先分配一定量的、大小相等的内存块,当有需要时直接从内存池中取。这样做的一个显著优点是避免了内存碎片,提高了内存分配效率。
2 一个简单的内存池实现代码
从内存中分配大片空间后,一般都会再分块进行管理,例如内存池大小是32M,可以以4K为单位分块。对内存池中的管理一般有两种方法:
(1) 用带头结点的list表示空闲的内存块,list中头结点存储下一个空闲的内存块。例如类BufferPool。
(2)用队列管理内存块。例如代码中类BufferQueueNode。
//myBufferPool.h
//Author:Winter Chen//Created:2013-4-18
//此文件设计一个内存池
//
#ifndef MYBUFFERPOOL_H
#define MYBUFFERPOOL_H
class BufferPool{
public:
BufferPool():mPool(0),mPoolSize(0),
mPageSize(0),mTotalPagesAmount(0),
mFreePagesCount(0),mFreeListPtr(0){}
~BufferPool(){Destroy();}
int Creat(unsigned int poolSize, bool mmapMemory = 0, bool lockMemory = 0);
void Destroy();
char* Get();
char* Get(unsigned int size);
bool Reclaim(char *ptr);
bool Reclaim(char *ptr, unsigned int size);
bool IsEmpty(){ return mFreePagesCount <= 0 ? 1 : 0;}
bool IsFull(){ return mFreePagesCount == mTotalPagesAmount? 1 : 0;}
unsigned int GetFreePagesCount(){return mFreePagesCount;}
unsigned int GetPoolSize(){return mPoolSize;}
private:
void *mPool;
unsigned int mPoolSize;
unsigned int mPageSize;
unsigned int mTotalPagesAmount;
unsigned int mFreePagesCount;
int *mFreeListPtr;
bool mIsMmap;
};
class BufferQueueNode{
public:
BufferQueueNode():mBufferPtr(0), mNext(this), mPrev(this){}
~BufferQueueNode(){
if(mBufferPtr)
delete mBufferPtr;
mBufferPtr = 0;
mNext = 0;
mPrev = 0;
}
char *mBufferPtr;
BufferQueueNode *mNext;
BufferQueueNode *mPrev;
};
class BufferPoolQueue{
public:
BufferPoolQueue():mPoolSize(0),
mDatalet(0), mHead(0), mPool(0){}
~BufferPoolQueue(){Destroy();}
int Creat(unsigned int poolSize, bool mmapMemory = 0, bool lockMemory = 0);
void Destroy();
void Enqueue(BufferQueueNode *inNode);
BufferQueueNode *Dequeue();
BufferQueueNode *Allocate();
void Reclaim(BufferQueueNode *inNode);
bool IsEmpty(){ return ((mHead == NULL) || (mHead->mNext == mHead)) ? 1 : 0;}
unsigned int GetPoolSize(){return mPoolSize;}
//unsigned int GetFreepoolsize();
private:
void *mPool;
unsigned int mPoolSize;
unsigned int mDatalet;
BufferQueueNode *mHead;
bool mIsMmap;
};
#endif
//**************************************************************************************//
//myBufferPool.cc
//Author:Winter Chen
//Created:2013-4-18
#include "myBufferPool.h"
#include <errno.h>
#include <iostream>
#include <sys/mman.h>
using namespace std;
int
BufferPool::Creat(unsigned int poolSize, bool mmapMemory, bool lockMemory){
mPageSize = sysconf(_SC_PAGESIZE);
mIsMmap = mmapMemory;
mTotalPagesAmount = poolSize/mPageSize + 1;
mPoolSize = mTotalPagesAmount*mPageSize;
cout << "mPageSize = " << mPageSize << " mTotalPagesAmount = " << mTotalPagesAmount <<" mPoolSize = "<< mPoolSize << endl;
if(mIsMmap){
mPool = mmap(0, mPoolSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (mPool == MAP_FAILED) {
mPool = 0;
return errno;
}
}
else
mPool = new char[mPoolSize];
//mlock:通过mlock可以将进程使用的部分
//或者全部的地址空间锁定在物理内存中,防止其被交换到swap空间
if(lockMemory && mlock(mPool, mPoolSize) != 0){
Destroy();
return errno;
}
mFreeListPtr = new int[mTotalPagesAmount+ 1];
mFreePagesCount = 0;
while(mFreePagesCount < mTotalPagesAmount){
mFreeListPtr[mFreePagesCount] = mFreePagesCount+1;
mFreePagesCount++;
}
mFreeListPtr[mTotalPagesAmount] = 0;
return 0;
}
bool
BufferPool::Reclaim(char *ptr){
if(IsFull())
return 0;
int pageNum = (ptr - (char*)mPool)/mPageSize + 1;
if(pageNum >= mTotalPagesAmount)
return 0;
mFreeListPtr[pageNum] = mFreeListPtr[0];
mFreeListPtr[0] = pageNum;
mFreePagesCount++;
return 1;
}
char*
BufferPool::Get(){
if(IsEmpty()){
cout << "empty!!!" << endl;
return NULL;
}
char *res;
res = (char*)mPool + (mFreeListPtr[0]-1) * mPageSize;
mFreeListPtr[0] = mFreeListPtr[mFreeListPtr[0]];
mFreePagesCount--;
cout << "get a buffer, address is :" << (void*)res << endl;
return res;
}
void
BufferPool::Destroy(){
delete [] mFreeListPtr;
mFreeListPtr = 0;
if(mIsMmap){
if (mPool && munmap(mPool, mPoolSize) != 0) {
cout <<"munmap error: " << errno <<endl;
}
}
else
delete [] mPool;
mPool = 0;
mPoolSize = 0;
mTotalPagesAmount = 0;
mFreePagesCount = 0;
}
int
BufferPoolQueue::Creat(unsigned int poolSize, unsigned int datalet, bool mmapMemory, bool lockMemory){
unsigned int pageSize = sysconf(_SC_PAGESIZE);
mPoolSize = (poolSize/pageSize + 1)*pageSize;
if(datalet <= 0)
return 0;
mDatalet = datalet;
//cout << "mPageSize = " << mPageSize << " mTotalPagesAmount = " << mTotalPagesAmount <<" mPoolSize = "<< mPoolSize << endl;
if(mmapMemory){
mPool = mmap(0, mPoolSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (mPool == MAP_FAILED) {
mPool = 0;
return errno;
}
}
else
mPool = new char[mPoolSize];
//mlock:通过mlock可以将进程使用的部分
//或者全部的地址空间锁定在物理内存中,防止其被交换到swap空间
if(lockMemory && mlock(mPool, mPoolSize) != 0){
Destroy();
return errno;
}
//create the head node of queue
mHead = new BufferQueueNode();
char pos = 0;
char *ptr = (char*) mPool;
while(pos < (mPoolSize - datalet)){
BufferQueueNode *p = new BufferQueueNode();
ptr += pos;
p->mBufferPtr = ptr;
Enqueue(p);
pos += datalet;
}
return 1;
}
void
BufferPoolQueue::Reclaim(BufferQueueNode *inNode){
Enqueue(inNode);
}
BufferQueueNode *
BufferPoolQueue::Allocate(){
return Dequeue();
}
void
BufferPoolQueue::Enqueue(BufferQueueNode *inNode){
inNode->mPrev = mHead->mPrev;
inNode->mNext = mHead;
mHead->mPrev->mNext = inNode;
mHead->mPrev = inNode;
}
BufferQueueNode *
BufferPoolQueue::Dequeue(){
if(IsEmpty())
return NULL;
BufferQueueNode *p = mHead->mNext;
p->mPrev->mNext = p->mNext;
p->mNext->mPrev= p->mPrev;
p->mPrev = p->mNext = 0;
return p;
}
void
BufferPoolQueue::Destroy(){
while(!IsEmpty()){
delete Dequeue();
}
delete mHead;
mHead = NULL;
if(mIsMmap){
if (mPool && munmap(mPool, mPoolSize) != 0) {
cout <<"munmap error: " << errno <<endl;
}
}
else
delete [] mPool;
mPool = 0;
mPoolSize = 0;
}
/*unsigned int
BufferPoolQueue::GetFreepoolsize(){
}
*/
注:以上代码没有考虑多线程情况,如果考虑多线程,需要在适当的地方加锁
参考资料:
http://baike.baidu.com/view/2659852.htm