C++ placement new与内存池
参考:https://blog.csdn.net/Kiritow/article/details/51314612
有些时候我们需要能够长时间运行的程序(例如监听程序,服务器程序)对于这些7*24运行的程序,我们不应该使用标准库提供的new 和 delete (malloc和free也算)。这是因为随着程序的运行,内存不断的被申请和被释放,频繁的申请和释放将会引发内存碎片、内存不足等问题,影响程序的正常运行。更多的时候核心程序不允许内存申请失败,更不允许异常的出现,因此必须保证每次内存申请都是成功的(一般都是内核程序,当然不希望被中断的后台程序也是如此)。在这种极端要求下,内存池的好处就大大的凸现出来了。
在C++中,可以通过placement new 来实现内存池。当然boost也有实现的内存池成品(boost::pool),这里不做过多解释。
下面是一段使用placement new的代码
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
void* GlobalBuffer=nullptr;
void InitGlobalBuffer()
{
GlobalBuffer=malloc(10240);
cout<<"GlobalBuffer Initialized. Pointer="<<GlobalBuffer<<",size= 10240"<<endl;
}
void DestroyGlobalBuffer()
{
free(GlobalBuffer);
}
class STK
{
public:
STK()
{
cout<<"In STK::STK(), this="<<this<<endl;
}
~STK()
{
cout<<"In STK::~STK(), this="<<this<<endl;
}
private:
int a,b,c;
};
int main()
{
cout<<"Main Start"<<endl;
InitGlobalBuffer();
STK* pstk=new (GlobalBuffer) STK;
pstk->~STK();
DestroyGlobalBuffer();
return 0;
}
上面的代码中,通过调用InitGlobalBuffer()来实现全局内存池的初始化(当然也可以封装成一个内存池类等等...),接下来,
STK* pstk=new (GlobalBuffer) STK;
这行代码在已经分配的内存(内存池)上构造对象。这个构造过程不会因为内存不足而抛出异常或者失败。(但是构造函数仍可能抛出异常导致terminate,这一点需要注意)
构造对象成功之后就可以正常使用此对象了。
需要注意的是,对象使用完毕之后需要手动进行析构函数的调用,如下
pstk->~STK();
这一步将调用STK类的析构函数STK::~STK(),但是内存并不会被释放。
最后通过DestroyGlobalBuffer()实现对全局内存池的释放。
内存池技术能够显著的减少内存申请时间,完全避免了内存碎片、内存不足等问题。与内存池相关的技术还有很多,在此就不详细叙述了。