一个简单化版本的内存池实现
一个简化版本的内存池实现
下面是个简答的测试代码:
测试代码如下:
最近写的一个程序中需要频繁的申请和释放零碎的内存块,这些内存块的大小却只有简单的几种。如果直接使用系统调用malloc/free、new/delete进行内存分配和释放,则效率很低。程序运行时间长了会产生大量的内存碎片。想起uC/OS-II 里面提供了个内存分配单元,正好满足我的需要。就把里面相关的代码扒了出来。写成了一个内存池的类。
这个内存池的功能非常的简单,初始化时分配一大块内存,然后将各个小内存块串成一个单项链表。每次分配内存块时从链表的头上去取一个内存块。回收内存块时也是将内存块插到链表的开头处。
这个类的结构如下:
#ifndef MEMPOOL_H #define MEMPOOL_H #define MEM_NO_ERR 0 #define MEM_INVALID_ADDR 1 #define MEM_INVALID_BLKS 2 #define MEM_INVALID_SIZE 3 #define MEM_INVALID_PART 4 #define MEM_INVALID_PBLK 5 #define MEM_FULL 6 class MemPool { public: MemPool(); ~MemPool(); int create (int nblocks, unsigned int blocksize); void* get( void ); int release ( void *pblk ); int blocks( void ) const {return m_memNBlks;}; int frees( void ) const {return m_memNFree;}; private: char *m_memAddr; /* Pointer to beginning of memory partition */ char *m_memFreeList; /* Pointer to list of free memory blocks */ int m_memBlkSize; /* Size (in bytes) of each block of memory */ int m_memNBlks; /* Total number of blocks in this partition */ int m_memNFree; /* Number of memory blocks remaining in this */ }; #endif
create 函数初始化内存池。主要的工作就是分配内存,然后将内存块串起来形成一个链表。因为要用指针形成链表,因此要求内存块的大小至少要能容纳一个指针。
get 函数获得一个内存块,如果没有剩余的内存块了,就返回 null。
release 函数回收内存块。
blocks 函数返回内存池总共有多少内存块。
frees 函数返回内存池还剩多少剩余的内存块。
代码实现如下:
#include <stddef.h> #include "MemPool.h" MemPool::MemPool() { m_memAddr = NULL; m_memFreeList = NULL; m_memBlkSize = 0; m_memNBlks = 0; m_memNFree = 0; } MemPool::~MemPool() { if(m_memAddr != NULL) { delete [] m_memAddr; } } int MemPool::create ( int nblks, unsigned int blksize ) { if( m_memAddr != NULL ) { delete [] m_memAddr; } m_memAddr = new char[nblks * blksize]; if ( m_memAddr == NULL ) { return MEM_INVALID_ADDR; } if ( nblks < 2 ) { /* Must have at least 2 blocks per partition */ return MEM_INVALID_BLKS; } if ( blksize < sizeof(void *) ) { /* Must contain space for at least a pointer */ return MEM_INVALID_SIZE; } void ** p = (void **)m_memAddr; char *pblk = m_memAddr + blksize; for (int i = 0; i < (nblks - 1); i++) { *p = (void *) pblk; p = (void **) pblk; pblk = pblk + blksize; } *p = (void *)0; m_memFreeList = m_memAddr; m_memNBlks = nblks; m_memNFree = nblks; return MEM_NO_ERR; } void * MemPool::get( void ) { void *pblk; if (m_memNFree > 0) { /* See if there are any free memory blocks */ pblk = m_memFreeList; /* Yes, point to next free memory block */ m_memFreeList = (char *) *(void **)pblk; /* Adjust pointer to new free list */ m_memNFree--;/* One less memory block in this partition */ return (pblk); /* Return memory block to caller */ } return ((void *)0); } int MemPool::release ( void *pblk ) { if (pblk == (void *)0) { /* Must release a valid block */ return (MEM_INVALID_PBLK); } if (m_memNFree >= m_memNBlks) { /* Make sure all blocks not already returned */ return (MEM_FULL); } /* Insert released block into free block list */ *(void **)pblk = m_memFreeList; m_memFreeList = (char *) pblk; m_memNFree++; /* One more memory block in this partition */ return (MEM_NO_ERR); /* Notify caller that memory block was released */ }
下面是个简答的测试代码:
#include <iostream> #include "MemPool.h" using namespace std; typedef struct { unsigned char *ImageData; int SizeX; int SizeY; int ImageID; double Timestamp; double TransferTime; unsigned int PacketCount; }IMAGE_INFO; int main() { IMAGE_INFO * p[15]; MemPool mem; mem.create(15, sizeof(IMAGE_INFO)); for(int i = 0; i < 10; i++) { p[i] = (IMAGE_INFO *)mem.get(); cout << "p[" << i << "] addr = " << p[i] << endl; p[i]->SizeX = i; p[i]->SizeY = i; } for(int i = 1; i < 10; i++) { cout << "p[" << i << "]->SizeX = " << p[i]->SizeX << endl; mem.release(p[i]); } cout << "mem.blocks()" << mem.blocks() << endl; cout << "mem.frees()" << mem.frees() << endl; return 0; }
这个测试程序的运行结果如下:
p[0] addr = 0xac1358 p[1] addr = 0xac1380 p[2] addr = 0xac13a8 p[3] addr = 0xac13d0 p[4] addr = 0xac13f8 p[5] addr = 0xac1420 p[6] addr = 0xac1448 p[7] addr = 0xac1470 p[8] addr = 0xac1498 p[9] addr = 0xac14c0 p[1]->SizeX = 1 p[2]->SizeX = 2 p[3]->SizeX = 3 p[4]->SizeX = 4 p[5]->SizeX = 5 p[6]->SizeX = 6 p[7]->SizeX = 7 p[8]->SizeX = 8 p[9]->SizeX = 9 mem.blocks()15 mem.frees()14
最后多说一句,如果程序中多个线程要访问同一个内存池,那个需要给 get 和 release 函数加锁。
另外,这个代码其实可以用C++的类模版来实现。下面是用了类模版技术的一个实现:
#ifndef MEMPOOL2_H_INCLUDED #define MEMPOOL2_H_INCLUDED #define MEM_NO_ERR 0 #define MEM_INVALID_ADDR 1 #define MEM_INVALID_BLKS 2 #define MEM_INVALID_SIZE 3 #define MEM_INVALID_PART 4 #define MEM_INVALID_PBLK 5 #define MEM_FULL 6 template < typename T > class MemPool2 { public: MemPool2(); ~MemPool2(); int create (int nblocks); T* get( void ); int release ( T *pblk ); int blocks( void ) const {return m_NBlocks;}; int frees( void ) const {return m_NFree;}; private: T *m_addr; /* Pointer to beginning of memory partition */ void *m_freeList; /* Pointer to list of free memory blocks */ int m_blockSize; /* Size (in bytes) of each block of memory */ int m_NBlocks; /* Total number of blocks in this partition */ int m_NFree; /* Number of memory blocks remaining in this */ }; template < typename T > MemPool2<T>::MemPool2() { m_addr = NULL; m_freeList = NULL; m_blockSize = sizeof(T); m_NBlocks = 0; m_NFree = 0; } template < typename T > MemPool2<T>::~MemPool2() { if(m_addr != NULL) { delete [] m_addr; } } template < typename T > int MemPool2<T>::create ( int nblocks ) { if( m_addr != NULL ) { delete [] m_addr; } m_addr = new T[nblocks]; if ( m_addr == NULL ) { return MEM_INVALID_ADDR; } if ( nblocks < 2 ) { /* Must have at least 2 blocks per partition */ return MEM_INVALID_BLKS; } if ( sizeof(T) < sizeof(void *) ) { /* Must contain space for at least a pointer */ return MEM_INVALID_SIZE; } void ** p = (void **)m_addr; T *pblock = m_addr; for (int i = 0; i < (nblocks - 1); i++) { pblock ++; *p = (void *) pblock; p = (void **) pblock; } *p = (void *)0; m_freeList = m_addr; m_NBlocks = nblocks; m_NFree = nblocks; return MEM_NO_ERR; } template < typename T > T * MemPool2<T>::get( void ) { T *pblk; if (m_NFree > 0) { /* See if there are any free memory blocks */ pblk = (T *) m_freeList; /* Yes, point to next free memory block */ m_freeList = (void *) *(void **)pblk; /* Adjust pointer to new free list */ m_NFree--;/* One less memory block in this partition */ return (pblk); /* Return memory block to caller */ } return ((T *)0); } template < typename T > int MemPool2<T>::release ( T *pblock ) { if (pblock == NULL) { /* Must release a valid block */ return (MEM_INVALID_PBLK); } if (m_NFree >= m_NBlocks) { /* Make sure all blocks not already returned */ return (MEM_FULL); } /* Insert released block into free block list */ *(void **)pblock = m_freeList; m_freeList = (void *) pblock; m_NFree++; /* One more memory block in this partition */ return (MEM_NO_ERR); /* Notify caller that memory block was released */ } #endif // MEMPOOL2_H_INCLUDED
测试代码如下:
#include <iostream> #include "MemPool2.h" using namespace std; typedef struct { unsigned char *ImageData; int SizeX; int SizeY; int ImageID; double Timestamp; double TransferTime; unsigned int PacketCount; }IMAGE_INFO; int main() { IMAGE_INFO * p[15] = {0}; MemPool2<IMAGE_INFO> mem; mem.create(5); for(int i = 0; i < 7; i++) { p[i] = mem.get(); if(p[i] != NULL) { cout << "p[" << i << "] addr = " << p[i] << endl; p[i]->SizeX = i; p[i]->SizeY = i; } } for(int i = 0; i < 9; i++) { if(p[i] != NULL) { cout << "p[" << i << "]->SizeX = " << p[i]->SizeX << endl; } mem.release(p[i]); } cout << "mem.blocks()" << mem.blocks() << endl; cout << "mem.frees()" << mem.frees() << endl; return 0; }