使用内存池进行内存管理 -
内存池是预先分配相同大小的内存块的方式。
例如,同一类的各种对象。因此,更多的是设计软件的“内存模型”。
示例 - 动画 gif 具有各种帧。假设每个帧只需要最大 1024 KB。
另外,如果我们知道最多只能有两个帧,那么我们可以通过为每个帧预先分配内存来避免碎片。
[note] - 内存池更适用于我们在设计时了解系统行为的情况。
因此,内存池的概念并不适用于任何地方。
//================================================= ==============================
// 名称:MemoryPool.cpp
// 作者 :
// 版本 :
// 版权所有 : SHREYAS JOSHI
// 描述 :
//================================================= ==============================
#include <iostream>
#include <malloc.h>
struct memPool
{
private:
char *m_poolPtr;
char *m_nextAvailAddr;
char *m_endAddr;
public:
/** Methods for the structure **/
void poolCreate(size_t size);
void poolDestroy();
void * poolAlloc(size_t size);
memPool():m_poolPtr(NULL),m_nextAvailAddr(NULL),m_endAddr(NULL)
{
std::cout<<"memPool constructor Invoked"<<std::endl;
}
~memPool()
{
std::cout<<"memPool Destructor Invoked"<<std::endl;
m_poolPtr = NULL;
m_nextAvailAddr = NULL;
m_endAddr = NULL;
}
};
/** Create a Pool of memory - makes a program hassle free of doing malloc multiple times **/
/** Also, Fragmentation can be avoided with the Memory Pool concept **/
/** A pool concept is useful, when you know at design time.how much memory is required for
the similar type of objects in total**/
void memPool::poolCreate(size_t size)
{
m_poolPtr = (char *) malloc(size);
if(m_poolPtr == NULL)
{
std::cout<<"Pool Create Failed"<<std::endl;
//printf("Pool Create Failed \r\n");
}
m_nextAvailAddr = m_poolPtr;
/** note the addressing starts from zero - thus you have already counted zero**/
m_endAddr = m_poolPtr + size - 1;
//printf("The Pool Head Pointer = %p \r\n",m_poolPtr);
std::cout<<"Pool Head Pointer = "<<static_cast<void *>(m_poolPtr)<<std::endl;
//printf("The Pool m_nextAvailAddr = %p \r\n",m_nextAvailAddr);
std::cout<<"Pool m_nextAvailAddr = "<<static_cast<void *>(m_nextAvailAddr)<<std::endl;
//printf("The Pool m_endAddr = %p \r\n",m_endAddr);
std::cout<<"Pool m_endAddr = "<<static_cast<void *>(m_endAddr)<<std::endl;
}
/** Destroy the entire pool in one shot ********/
void memPool::poolDestroy()
{
free(m_poolPtr);
/** Remember free first then assign to NULL **/
m_poolPtr = NULL;
/** Update Housekeeping--data structure **/
m_nextAvailAddr = NULL;
m_endAddr = NULL;
}
/** Allocate some space from the pool ********/
/** Check if the space is available or not **/
/** Do the housekeeping - update the nextAvail Addr in the structure**/
void * memPool::poolAlloc(size_t size)
{
void *mem = NULL;
if( (m_endAddr != NULL) && (m_nextAvailAddr != NULL))
{
/** This is according to fencing problem - add 1 when you are find a difference of sequence to calculate the space within **/
size_t availableSize = m_endAddr - m_nextAvailAddr + 1;
/** check for the availability **/
if(size > availableSize )
{
//std::cout<<"Warning!! the available size = "<<availableSize<< "requested size = "<<size<<std::endl;
printf("Warning!! the available size = %u and requested size = %u \r\n",availableSize, size);
mem = NULL;
}
else
{
/** store the available pointer to the user**/
mem = m_nextAvailAddr;
//printf("The user return pointer is = %p \r\n ",mem);
std::cout<<"The user return pointer is = "<<static_cast <void *>(mem)<<std::endl;
/*** advance the next available pointer **/
m_nextAvailAddr += size;
//printf("The next available pointer is = %p \r\n ",m_nextAvailAddr);
std::cout<<"The next available pointer is = "<<static_cast<void *>(m_nextAvailAddr)<<std::endl;
}
}
return mem;
}
int main(int argc, char *argv[])
{
memPool gifAnimatedImageFramesBlk;
/** Let's say each frame needs 512 kb **/
char *gifFrame1 = NULL;
char *gifFrame2 = NULL;
char *gifFrame3 = NULL;
/** 1 MB Pool for the GIF IMAGE FRAMES **/
gifAnimatedImageFramesBlk.poolCreate(1024*1024*1024);
/*** 512 KB **/
gifFrame1 = (char *)gifAnimatedImageFramesBlk.poolAlloc(512*1024*1024);
//printf("Got the gifFrame1..pointer- == %p \r\n ",gifFrame1);
std::cout<<"Got the gifFrame1..pointer- == "<<static_cast<void *>(gifFrame1)<<std::endl;
/** again 512 MB **/
gifFrame2 = (char *)gifAnimatedImageFramesBlk.poolAlloc(512*1024*1024);
std::cout<<"Got the gifFrame2..pointer- == "<<static_cast<void *>(gifFrame2)<<std::endl;
//printf("Got the gifFrame2..pointer- == %p \r\n ",gifFrame2);
/*************Exhausted the pool memory now **************/
/** This will fail ****************/
gifFrame3 = (char *)gifAnimatedImageFramesBlk.poolAlloc(1);
std::cout<<"Got the gifFrame3..pointer- == "<<static_cast<void *>(gifFrame3)<<std::endl;
//printf("Got the gifFrame3..pointer- == %p \r\n ",gifFrame3);
/*****Destroy the Pool now *****************/
gifAnimatedImageFramesBlk.poolDestroy();
gifFrame3 = (char *)gifAnimatedImageFramesBlk.poolAlloc(1);
std::cout<<"Got the gifFrame3..pointer- == "<<static_cast<void *>(gifFrame3)<<std::endl;
//printf("Got the gifFrame3..pointer- == %p \r\n ",gifFrame3);
gifFrame3 = (char *)gifAnimatedImageFramesBlk.poolAlloc(1);
std::cout<<"Got the gifFrame3..pointer- == "<<static_cast<void *>(gifFrame3)<<std::endl;
//printf("Got the gifFrame3..pointer- == %p \r\n ",gifFrame3);
return 0;
}
[note] - 为了在 C++ 中使用 ostream::operator
内存池的优点
- 您可以避免内存碎片。即使系统需要内存空间,当所需的连续块大小不可用时,malloc() 也会失败。
- 预留空间,避免频繁使用malloc()和free()。这将节省时间。
- 当为许多子块调用 malloc() 时,管理/元数据与每个分配的子块相关联。这会
消耗不必要的空间。相反,一个大块分配将避免多个管理/元数据。
- 如果内存空间受到限制,那么很容易调查内存泄漏。如果 Pool 中的内存耗尽,则内存池将
返回 NULL。因此,您可以轻松隔离内存泄漏问题。