C++ placement new與記憶體池
阿新 • • 發佈:2019-02-01
有些時候我們需要能夠長時間執行的程式(例如監聽程式,伺服器程式)對於這些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()實現對全域性記憶體池的釋放。
記憶體池技術能夠顯著的減少記憶體申請時間,完全避免了記憶體碎片、記憶體不足等問題。與記憶體池相關的技術還有很多,在此就不詳細敘述了。