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()实现对全局内存池的释放。

内存池技术能够显著的减少内存申请时间,完全避免了内存碎片、内存不足等问题。与内存池相关的技术还有很多,在此就不详细叙述了。

posted @ 2019-10-18 20:16  IUNI_JM  阅读(669)  评论(0编辑  收藏  举报