程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 開源C++函數庫Boost內存池使用與測試

開源C++函數庫Boost內存池使用與測試

編輯:C++入門知識

 Boost庫是一個可移植的開源C++函數庫,鑒於STL(標准模板庫)已經成為C++語言的一個組成部分,可以毫不誇張的說,Boost是目前影響最大的通用C++庫。Boost庫由C++標准委員會庫工作組成員發起,其中有些內容有望成為下一代C++標准庫內容,是一個“准”標准庫。
  Boost內存池,即boost.pool庫,是由Boost提供的一個用於內存池管理的開源C++庫。作為Boost中影響較大的一個庫,Pool已經被廣泛使用。
  1. 什麼是內存池“池”是在計算機技術中經常使用的一種設計模式,其內涵在於:將程序中需要經常使用的核心資源先申請出來,放到一個池內,由程序自己管理,這樣可以提高資源的使用效率,也可以保證本程序占有的資源數量。經常使用的池技術包括內存池、線程池和連接池等,其中尤以內存池和線程池使用最多。
  內存池(Memory Pool)是一種動態內存分配與管理技術。通常情況下,程序員習慣直接使用new、delete、malloc、free等API申請分配和釋放內存,導致的後果時:當程序長時間運行時,由於所申請內存塊的大小不定,頻繁使用時會造成大量的內存碎片從而降低程序和操作系統的性能。內存池則是在真正使用內存之前,先申請分配一大塊內存(內存池)留作備用,當程序員申請內存時,從池中取出一塊動態分配,當程序員釋放內存時,將釋放的內存再放入池內,並盡量與周邊的空閒內存塊合並。若內存池不夠時,則自動擴大內存池,從操作系統中申請更大的內存池。
  內存池的應用場景早期的內存池技術是為了專門解決那種頻繁申請和釋放相同大小內存塊的程序,因此早期的一些內存池都是用相同大小的內存塊鏈表組織起來的。
  Boost的內存池則對內存塊的大小是否相同沒有限制,因此只要是頻繁動態申請釋放內存的長時間運行程序,都適用Boost內存池。這樣可以有效減少內存碎片並提高程序運行效率。
  安裝Boost的pool庫是以C++頭文件的形式提供的,不需要安裝,也沒有lib或者dll文件,僅僅需要將頭文件包含到你的C++工程中就可以了。Boost的最新版本可以到http://www.boost.org/下載。
  2. 內存池的特征2.1 無內存洩露正確的使用內存池的申請和釋放函數不會造成內存洩露,更重要的是,即使不正確的使用了申請和釋放函數,內存池中的內存也會在進程結束時被全部自動釋放,不會造成系統的內存洩露。
  2.2 申請的內存數組沒有被填充例如一個元素的內存大小為A,那麼元素數組若包含n個元素,則該數組的內存大小必然是A*n,不會有多余的內存來填充該數組。盡管每個元素也許包含一些填充的東西。
  2.3 任何數組內存塊的位置都和使用operator new[]分配的內存塊位置一致這表明你仍可以使用那些通過數組指針計算內存塊位置的算法。
  2.4 內存池要比直接使用系統的動態內存分配快這個快是概率意義上的,不是每個時刻,每種內存池都比直接使用new或者malloc快。例如,當程序使用內存池時內存池恰好處於已經滿了的狀態,那麼這次內存申請會導致內存池自我擴充,肯定比直接new一塊內存要慢。但在大部分時候,內存池要比new或者malloc快很多。
  3. 內存池效率測試3.1 測試1:連續申請和連續釋放分別用內存池和new連續申請和連續釋放大量的內存塊,比較其運行速度,代碼如下:#include "stdafx.h" #include <iostream> #include <ctime> #include <vector> #include <boost/pool/pool.hpp> #include <boost/pool/object_pool.hpp> using namespace std;using namespace boost;
  const int MAXLENGTH = 100000;
  int main ( )
  { boost::pool<> p(sizeof(int));int* vec1[MAXLENGTH];int* vec2[MAXLENGTH];
  clock_t clock_begin = clock();for (int i = 0; i < MAXLENGTH; ++i)
  { vec1[i] = static_cast<int*>(p.malloc());} for (int i = 0; i < MAXLENGTH; ++i)
  { p.free(vec1[i]);vec1[i] = NULL;}
  clock_t clock_end = clock();cout<<"程序運行了 "<<clock_end-clock_begin<<" 個系統時鐘"<<endl;
  clock_begin = clock();for (int i = 0; i < MAXLENGTH; ++i)
  { vec2[i] = new int;} for (int i = 0; i < MAXLENGTH; ++i)
  { delete vec2[i];vec2[i] = NULL;}
  clock_end = clock();cout<<"程序運行了 "<<clock_end-clock_begin<<" 個系統時鐘"<<endl;
  return 0;}測試環境:VS2008,WindowXP SP2,Pentium 4 CPU雙核,1.5GB內存。
  結論:在連續申請和連續釋放10萬塊內存的情況下,使用內存池耗時是使用new耗時的47.46%.
  3. 內存池效率測試3.1 測試1:連續申請和連續釋放分別用內存池和new連續申請和連續釋放大量的內存塊,比較其運行速度,代碼如下:#include "stdafx.h" #include <iostream> #include <ctime> #include <vector> #include <boost/pool/pool.hpp> #include <boost/pool/object_pool.hpp> using namespace std;using namespace boost;
  const int MAXLENGTH = 100000;
  int main ( )
  { boost::pool<> p(sizeof(int));int* vec1[MAXLENGTH];int* vec2[MAXLENGTH];
  clock_t clock_begin = clock();for (int i = 0; i < MAXLENGTH; ++i)
  { vec1[i] = static_cast<int*>(p.malloc());} for (int i = 0; i < MAXLENGTH; ++i)
  { p.free(vec1[i]);vec1[i] = NULL;}
  clock_t clock_end = clock();cout<<"程序運行了 "<<clock_end-clock_begin<<" 個系統時鐘"<<endl;
  clock_begin = clock();for (int i = 0; i < MAXLENGTH; ++i)
  { vec2[i] = new int;} for (int i = 0; i < MAXLENGTH; ++i)
  { delete vec2[i];vec2[i] = NULL;}
  clock_end = clock();cout<<"程序運行了 "<<clock_end-clock_begin<<" 個系統時鐘"<<endl;
  return 0;}測試環境:VS2008,WindowXP SP2,Pentium 4 CPU雙核,1.5GB內存。
  結論:在連續申請和連續釋放10萬塊內存3.2 測試2:反復申請和釋放小塊內存代碼如下:#include "stdafx.h" #include <iostream> #include <ctime> #include <vector> #include <boost/pool/pool.hpp> #include <boost/pool/object_pool.hpp> using namespace std;using namespace boost;
  const int MAXLENGTH = 500000;
  int main ( )
  { boost::pool<> p(sizeof(int));
  clock_t clock_begin = clock();for (int i = 0; i < MAXLENGTH; ++i)
  { int * t = static_cast<int*>(p.malloc());p.free(t);} clock_t clock_end = clock();cout<<"程序運行了 "<<clock_end-clock_begin<<" 個系統時鐘"<<endl;
  clock_begin = clock();for (int i = 0; i < MAXLENGTH; ++i)
  { int* t = new int;delete t;} clock_end = clock();cout<<"程序運行了 "<<clock_end-clock_begin<<" 個系統時鐘"<<endl;
  return 0;}測試結果如下:
  結論:在反復申請和釋放50萬次內存的情況下,使用內存池耗時是使用new耗時的64.34%.的情況下,使用內存池耗時是使用new耗時的47.46%.
  3.3 測試3:反復申請和釋放C++對象C++對象在動態申請和釋放時,不僅要進行內存操作,同時還要調用構造和析購函數。因此有必要對C++對象也進行內存池的測試。
  代碼如下:#include "stdafx.h" #include <iostream> #include <ctime> #include <vector> #include <boost/pool/pool.hpp> #include <boost/pool/object_pool.hpp> using namespace std;using namespace boost;
  const int MAXLENGTH = 500000;class A { public:A()
  { m_i++;} ~A( )
  { m_i——;} private:int m_i;};
  int main ( )
  { object_pool<A> q;
  clock_t clock_begin = clock();for (int i = 0; i < MAXLENGTH; ++i)
  { A* a = q.construct();q.destroy(a);}
  clock_t clock_end = clock();cout<<"程序運行了 "<<clock_end-clock_begin<<" 個系統時鐘"<<endl;
  clock_begin = clock();for (int i = 0; i < MAXLENGTH; ++i)
  { A* a = new A;delete a;} clock_end = clock();cout<<"程序運行了 "<<clock_end-clock_begin<<" 個系統時鐘"<<endl;
  return 0;}測試結果如下:
  結論:在反復申請和釋放50萬個C++對象的情況下,使用內存池耗時是使用new耗時的112.03%.這是因為內存池的construct和destroy函數增加了函數調用次數的原因。這種情況下使用內存池並不能獲得性能上的優化。
  4. Boost內存池的分類Boost內存池按照不同的理念分為四類。主要是兩種理念的不同造成了這樣的分類。
  一是Object Usage和Singleton Usage的不同。Object Usage意味著每個內存池都是一個可以創建和銷毀的對象,一旦內存池被銷毀則其所分配的所有內存都會被釋放。Singleton Usage意味著每個內存池都是一個被靜態分配的對象,直至程序結束才會被銷毀,這也意味著這樣的內存池是多線程安全的。只有使用release_memory或者 purge_memory方法才能釋放內存。
  二是內存溢出的處理方式。第一種方式是返回NULL代表內存池溢出了;第二種方式是拋出異常代表內存池溢出。
  根據以上的理念,boost的內存池分為四種。
  4.1 Pool Pool是一個Object Usage的內存池,溢出時返回NULL. 4.2 object_pool object_pool與pool類似,唯一的區別是當其分配的內存釋放時,它會嘗試調用該對象的析購函數。
  4.3 singleton_pool singleton_pool是一個Singleton Usage的內存池,溢出時返回NULL. 4.4 pool_alloc pool_alloc是一個Singleton Usage的內存池,溢出時拋出異常。
  5. 內存池溢出的原理與解決方法5.1 必然溢出的內存內存池簡化了很多內存方面的操作,也避免了一些錯誤使用內存對程序造成的損害。但是,使用內存池時最需要注意的一點是要處理內存池溢出的情況。
  沒有不溢出的內存,看看下面的代碼:#include "stdafx.h" #include <iostream> #include <ctime> #include <vector> #include <boost/pool/pool.hpp> #include <boost/pool/object_pool.hpp> using namespace std;using namespace boost;
  int _tmain(int argc, _TCHAR* argv[])
  { clock_t clock_begin = clock();int iLength = 0;for (int i = 0; ;++i)
  { void* p = malloc(1024*1024);&

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved