“池化技術”漫談 - 線程池,內存池,連接池……

池化技術 - 簡單點來說,就是提前保存大量的資源,以備不時之需,O(∩_∩)O,對於線程,內存,oracle的連接對象等等,這些都是資源,程序中當你創建一個線程或者在堆上申請一塊內存時,都涉及到很多系統調用,也是非常消耗CPU的,如果你的程序需要很多類似的工作線程或者需要頻繁的申請釋放小塊內存,如果沒有在這方面進行優化,那很有可能這部分代碼將會成爲影響你整個程序性能的瓶頸。池化技術主要有線程池,內存池,連接池,對象池等等,對象池就是提前創建很多對象,將用過的對象保存起來,等下一次需要這種對象的時候,再拿出來重複使用,連接池比較典型的有oracle的連接池,瞭解不深。

下面主要談談線程池和內存池,因爲這兩種技術的通用性和實用性也是比較強的,描述語言C++,其實線程池的話用什麼實現都可以。

 

先來談談線程池技術,線程池的框架早就有先輩給我們想好了,也就不用我們去冥思苦想了,我們要做的就是把先輩的想法發現即可。

其實線程池的原理很簡單,類似於操作系統中的緩衝區的概念,它的流程如下:先啓動若干數量的線程,並讓這些線程都處於睡眠狀態,當客戶端有一個新請求時,就會喚醒線程池中的某一個睡眠線程,讓它來處理客戶端的這個請求,當處理完這個請求後,線程又處於睡眠狀態。可能你也許會問:爲什麼要搞得這麼麻煩,如果每當客戶端有新的請求時,我就創建一個新的線程不就完了?這也許是個不錯的方法,因爲它能使得你編寫代碼相對容易一些,但你卻忽略了一個重要的問題?性能!尤其是對於服務器程序尤爲重要,服務器程序會先初始化很多線程在那裏等待,當有客戶連接時,就激活其中的一個線程來處理客戶請求,對於不支持動態增加的線程池,如果沒有等待線程,客戶就必學等待,而對於能動態增加線程的線程池,則可以像線程池中新加一個線程。

下面是一個用c++實現的線程池,支持動態增減線程數量:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   KThreadPool.h
  3. //  創建者     :   magicTong
  4. //  創建時間    :   2008-10-23 15:02:31
  5. //  功能描述    :   線程池聲明
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #ifndef __KTHREADPOOL_H__
  10. #define __KTHREADPOOL_H__
  11. // -------------------------------------------------------------------------
  12. #include <windows.h>
  13. #include <list>
  14. using namespace std;
  15. // 線程函數指針定義 
  16. typedef DWORD (WINAPI *PTHREAD_FUNC_EX)(LPVOID lpThreadParameter);
  17. // 線程狀態枚舉
  18. typedef enum _enumKThreadStatus
  19. {
  20.     THREADRUN,      // 運行
  21.     THREADPAUSE,    // 暫停
  22. }
  23. KThreadStatus;
  24. // -------------------------------------------------------------------------
  25. // 類名       : KThread
  26. // 功能       : 線程類,可動態更換執行函數
  27. // 附註       : 
  28. // -------------------------------------------------------------------------
  29. class KThread
  30. {
  31. public:
  32.     // 構造
  33.     KThread();
  34.     // 析構
  35.     ~KThread();
  36.     // -------------------------------------------------------------------------
  37.     // 函數       : Init
  38.     // 功能       : 初始化函數
  39.     // 返回值  : bool 
  40.     // 附註       : 
  41.     // -------------------------------------------------------------------------
  42.     bool Init();
  43.     // -------------------------------------------------------------------------
  44.     // 函數       : Run
  45.     // 功能       : 運行線程
  46.     // 返回值  : bool 
  47.     // 附註       : 
  48.     // -------------------------------------------------------------------------
  49.     bool Run();
  50.     // -------------------------------------------------------------------------
  51.     // 函數       : Pause
  52.     // 功能       : 暫停線程
  53.     // 返回值  : bool 
  54.     // 附註       : 
  55.     // -------------------------------------------------------------------------
  56.     bool Pause();
  57.     // -------------------------------------------------------------------------
  58.     // 函數       : Join
  59.     // 功能       : 調用Join的線程將阻塞,直到該線程執行完畢
  60.     // 返回值  : void 
  61.     // 附註       : 
  62.     // -------------------------------------------------------------------------
  63.     void Join();
  64.     // -------------------------------------------------------------------------
  65.     // 函數       : SetProc
  66.     // 功能       : 設置線程運行的函數,和要傳給線程的參數
  67.     // 返回值  : void 
  68.     // 參數       : PTHREAD_FUNC_EX proc
  69.     // 參數       : void* lpParam
  70.     // 附註       : 
  71.     // -------------------------------------------------------------------------
  72.     void SetProc(PTHREAD_FUNC_EX proc, void* lpParam);
  73. protected:
  74.     KThread(KThread&){}
  75.     // 線程實際運行的函數
  76.     static DWORD WINAPI RealThreadProc(void* lpParam);
  77.     friend class KThreadPool;
  78. protected:
  79.     struct KThreadParam
  80.     {
  81.         PTHREAD_FUNC_EX proc;   // 用戶線程函數
  82.         void *lpParam;          // 用戶線程參數
  83.         KThread *pThread;       // 線程類對象
  84.     };
  85.     HANDLE              m_hThread;
  86.     DWORD               m_id;
  87.     KThreadParam        m_param;
  88.     KThreadStatus       m_status;
  89.     HANDLE              m_hEvt;
  90.     HANDLE              m_hMtx;
  91. };
  92. // -------------------------------------------------------------------------
  93. // 類名       : KThreadPool
  94. // 功能       : 線程池類聲明
  95. // 附註       : 
  96. // -------------------------------------------------------------------------
  97. class KThreadPool
  98. {
  99. public:
  100.     //構造,initNum初始情況線程數量
  101.     KThreadPool(int initNum);
  102.     //析構
  103.     ~KThreadPool();
  104.     // -------------------------------------------------------------------------
  105.     // 函數       : DoWork
  106.     // 功能       : 申請線程進行工作,proc工作函數,lpParam工作函數參數,run是否立即運行,返回線程ID
  107.     // 返回值  : DWORD 
  108.     // 參數       : PTHREAD_FUNC_EX proc
  109.     // 參數       : void *lpParam
  110.     // 參數       : bool run = true
  111.     // 附註       : 
  112.     // -------------------------------------------------------------------------
  113.     DWORD DoWork(PTHREAD_FUNC_EX proc, void *lpParam, bool run = true);
  114.     // -------------------------------------------------------------------------
  115.     // 函數       : Run
  116.     // 功能       : 運行線程,id線程ID
  117.     // 返回值  : bool 
  118.     // 參數       : DWORD id
  119.     // 附註       : 
  120.     // -------------------------------------------------------------------------
  121.     bool Run(DWORD id);
  122.     // -------------------------------------------------------------------------
  123.     // 函數       : Pause
  124.     // 功能       : 暫停運行線程,id線程ID
  125.     // 返回值  : bool 
  126.     // 參數       : DWORD id
  127.     // 附註       : 
  128.     // -------------------------------------------------------------------------
  129.     bool Pause(DWORD id);
  130.     //調整線程池大小爲size,返回調整後線程池大小
  131.     unsigned SetSize(unsigned size);
  132. protected:
  133.     list<KThread*> m_lst;
  134. };

實現:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   KThreadPool.cpp
  3. //  創建者     :   magicTong
  4. //  創建時間    :   2008-10-23 15:02:22
  5. //  功能描述    :   線程池定義
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #include "stdafx.h"
  10. #include "KThreadPool.h"
  11. // -------------------------------------------------------------------------
  12. // -------------------------------------------------------------------------
  13. // KThread類定義開始
  14. // -------------------------------------------------------------------------
  15. KThread::KThread(): m_hThread(NULL), 
  16.                     m_status(THREADPAUSE), 
  17.                     m_hEvt(0), 
  18.                     m_hMtx(0)
  19. {
  20. }
  21. KThread::~KThread()
  22. {
  23.     ::CloseHandle(m_hMtx);
  24.     if (::TerminateThread(m_hThread, -1) == 0)
  25.         return;
  26. }
  27. bool KThread::Init()
  28. {
  29.     m_hThread = ::CreateThread(
  30.                                 0, 
  31.                                 0, 
  32.                                 (PTHREAD_FUNC_EX)(KThread::RealThreadProc),
  33.                                 (void*)&m_param, 
  34.                                 CREATE_SUSPENDED, 
  35.                                 &m_id);
  36.     // 創建線程失敗
  37.     if (NULL == m_hThread)
  38.     {
  39.         return false;
  40.     }
  41.     m_param.proc = NULL;
  42.     m_param.lpParam = NULL;
  43.     m_param.pThread = this;
  44.     //自動復位
  45.     m_hEvt = ::CreateEvent(0, FALSE, FALSE, 0);
  46.     if (m_hEvt == 0)
  47.     {
  48.         ::CloseHandle(m_hThread);
  49.         return false;
  50.     }
  51.     m_hMtx = ::CreateMutex(0, 0, 0);
  52.     if (m_hMtx == 0)
  53.     {
  54.         ::CloseHandle(m_hEvt);
  55.         ::CloseHandle(m_hThread);
  56.         return false;
  57.     }
  58.     return true;
  59. }
  60. bool KThread::Run()
  61. {
  62.     ::WaitForSingleObject(m_hMtx, INFINITE);
  63.     if (m_status == THREADPAUSE)
  64.         if (::ResumeThread(m_hThread) == -1)
  65.         {
  66.             ::ReleaseMutex(m_hMtx);
  67.             return false;
  68.         }
  69.     
  70.     m_status = THREADRUN;
  71.     ::ReleaseMutex(m_hMtx);
  72.     return true;
  73. }
  74. bool KThread::Pause()
  75. {
  76.     ::WaitForSingleObject(m_hMtx, INFINITE);
  77.     if (m_status == THREADRUN)
  78.         if (::SuspendThread(m_hThread) == -1)
  79.         {
  80.             ::ReleaseMutex(m_hMtx);
  81.             return false;
  82.         }
  83.     m_status = THREADPAUSE;
  84.     ::ReleaseMutex(m_hMtx);
  85.     return true;
  86. }
  87. void KThread::Join()
  88. {
  89.     ::WaitForSingleObject(m_hEvt, INFINITE);
  90. }
  91. void KThread::SetProc(PTHREAD_FUNC_EX proc, void* lpParam)
  92. {
  93.     ::WaitForSingleObject(m_hMtx, INFINITE);
  94.     m_param.proc = proc;
  95.     m_param.lpParam = lpParam;
  96.     ::ReleaseMutex(m_hMtx);
  97. }
  98. DWORD WINAPI KThread::RealThreadProc(void* lpParam)
  99. {
  100.     PTHREAD_FUNC_EX proc;
  101.     KThreadParam *pp = (KThreadParam*)lpParam;
  102.     while (true)
  103.     {
  104.         proc = pp->proc;
  105.         if (proc)
  106.             (*proc)(pp->lpParam);
  107.         pp->proc = NULL;
  108.         pp->lpParam = NULL;
  109.         pp->pThread->Pause();
  110.         ::SetEvent(pp->pThread->m_hEvt);
  111.     }
  112. }
  113. // -------------------------------------------------------------------------
  114. // KThread類定義結束
  115. // -------------------------------------------------------------------------
  116. // -------------------------------------------------------------------------
  117. // KThreadPool類定義開始
  118. // -------------------------------------------------------------------------
  119. KThreadPool::KThreadPool(int initNum)
  120. {
  121.     KThread *pt;
  122.     for (int i = 0; i < initNum; i++)
  123.     {
  124.         pt = new KThread;
  125.         if (pt->Init())
  126.             m_lst.push_back(pt);
  127.     }
  128. }
  129. KThreadPool::~KThreadPool()
  130. {
  131.     list<KThread*>::iterator itBegin = m_lst.begin();
  132.     list<KThread*>::iterator itEnd = m_lst.end();
  133.     for ( ; itBegin != itEnd; itBegin++)
  134.     {
  135.         delete (*itBegin);
  136.     }
  137. }
  138. DWORD KThreadPool::DoWork(LPTHREAD_START_ROUTINE proc, void *lpParam, bool run)
  139. {
  140.     list<KThread*>::iterator itBegin = m_lst.begin();
  141.     list<KThread*>::iterator itEnd = m_lst.end();
  142.     for (; itBegin != itEnd; itBegin++)
  143.     {
  144.         if ((*itBegin)->m_param.proc == NULL && (*itBegin)->m_status == THREADPAUSE)
  145.         {
  146.             (*itBegin)->SetProc(proc, lpParam);
  147.             
  148.             // 立即運行
  149.             if (run)
  150.                 (*itBegin)->Run();
  151.             return (*itBegin)->m_id;
  152.         }
  153.     }
  154.     // 沒有空閒線程,新建一個新的線程,加入鏈表
  155.     KThread *pt = new KThread;
  156.     if (pt->Init())
  157.         m_lst.push_back(pt);
  158.     pt->SetProc(proc, lpParam);
  159.     if (run)
  160.         pt->Run();
  161.     return pt->m_id;
  162. }
  163. bool KThreadPool::Run(DWORD id)
  164. {
  165.     list<KThread*>::iterator itBegin = m_lst.begin();
  166.     list<KThread*>::iterator itEnd = m_lst.end();
  167.     for (; itBegin != itEnd; itBegin++)
  168.     {
  169.         if ((*itBegin)->m_id == id)
  170.         return ((*itBegin)->Run());
  171.     }
  172.     return false;
  173. }
  174. bool KThreadPool::Pause(DWORD id)
  175. {
  176.     list<KThread*>::iterator itBegin = m_lst.begin();
  177.     list<KThread*>::iterator itEnd = m_lst.end();
  178.     for (; itBegin != itEnd; itBegin++)
  179.     {
  180.         if ((*itBegin)->m_id == id)
  181.             return ((*itBegin)->Pause());
  182.     }
  183.     
  184.     return false;
  185. }
  186. // -------------------------------------------------------------------------
  187. // 函數       : KThreadPool::SetSize
  188. // 功能       : 修改線程池的大小
  189. // 返回值  : unsigned 
  190. // 參數       : unsigned size
  191. // 附註       : 如果小縮小線程池大小,謹慎使用
  192. // -------------------------------------------------------------------------
  193. unsigned KThreadPool::SetSize(unsigned size)
  194. {
  195.     unsigned nowsize = m_lst.size();
  196.     if (nowsize <= size)
  197.     {
  198.         KThread *pt;
  199.         unsigned inc = size - nowsize;
  200.         for (unsigned i = 0; i < inc; i++)
  201.         {
  202.             pt = new KThread;
  203.             if (pt->Init())
  204.             {
  205.                 m_lst.push_back(pt);
  206.             }
  207.         }
  208.         return size;
  209.     }
  210.     else
  211.     {
  212.         unsigned dec = nowsize - size;
  213.         list<KThread*>::iterator it = m_lst.begin();
  214.         list<KThread*>::iterator ite = m_lst.end();
  215.         list<KThread*>::iterator itemp;
  216.         unsigned i = 0;
  217.         for (; it != ite && i < dec;)
  218.         {
  219.             if ((*it)->m_status == THREADPAUSE)
  220.             {
  221.                 itemp = it++;
  222.                 delete ((*itemp));
  223.                 m_lst.erase(itemp);
  224.                 i++;
  225.                 continue;
  226.             }
  227.             it++;
  228.         }
  229.         ::Sleep(100 * i);
  230.         return m_lst.size();
  231.     }
  232. }
  233. // -------------------------------------------------------------------------
  234. // KThreadPool類定義結束
  235. // -------------------------------------------------------------------------

使用:

要定義一個線程函數,然後再將該函數和線程數量設置到內存池中,測試代碼如下:

  1. DWORD WINAPI threadFunc(LPVOID lpThreadParam);
  2. void CKThreadPoolExDlg::OnBtnCreate() 
  3. {
  4.     static i = 0;
  5.     if (!m_pThreadPool)
  6.     {
  7.         m_pThreadPool = new KThreadPool(1);
  8.     }
  9.     
  10.     m_pThreadPool->DoWork(threadFunc, thistrue);
  11.     i++;
  12.     if (i == 4)
  13.     {
  14.         m_pThreadPool->SetSize(10);
  15.     }
  16. }
  17. void CKThreadPoolExDlg::DoSomething()
  18. {
  19.     //MessageBox("O(∩_∩)O哈哈~");
  20.     while (true)
  21.     {
  22.         ::EnterCriticalSection(&m_cs);
  23.         DWORD id = GetCurrentThreadId();
  24.         CString cstr;
  25.         cstr.Format("線程 %d 正在運行...", id);
  26.         m_listInfo.InsertItem(m_listInfo.GetItemCount(), cstr);
  27.         ::LeaveCriticalSection(&m_cs);
  28.         ::Sleep(400);
  29.     }
  30. }
  31. DWORD WINAPI threadFunc(LPVOID lpThreadParam)
  32. {
  33.     CKThreadPoolExDlg *pdlg = (CKThreadPoolExDlg *)lpThreadParam;
  34.     pdlg->DoSomething();
  35.     return 0;
  36. }

代碼的詳細註釋我就不寫了,想弄懂原理的還是好好研究下再使用,我不保證裏面沒有BUG。

 

再來看看內存池的原理,我下面的參考資料裏面有幾篇文章講得不錯,想了解原理的可以去看看。

如何更好的管理在應用程序中內存的使用,同時提高內存使用的效率,這是值得每一個開發人員深思的問題。內存池(Memory pool)提供了一種比較可行的解決方案。首先是創建內存池。這個過程的主要任務是預先分配足夠大的內存,形成一個初步的“內存池”。分配內存,也就是用戶請求內存時,會返回內存池中一塊空閒的內存,並將其標誌置爲已使用,當然具體細節和方法有很多。釋放內存時,不是真正地調用free或是delete的過程,而是把內存放回內存池的過程。在把內存放入內存池的同時,要把標誌位置爲空閒。最後在應用程序結束時,要把內存池銷燬。這裏主要做的工作就是把內存池中的每一塊內存釋放。

使用內存池的好處:

1、減少了內存碎片的產生。這個可以從創建內存池的過程中看出。我們在創建內存池時,分配的都是一塊塊比較整的內存塊,這樣可以減少內存碎片的產生。

2、提高了內存的使用效率。這個可以從分配內存和釋放內存的過程中看出。每次的分配與釋放並不是去調用系統提供的函數或是操作符去操作實際的內存,而是在複用內存池中的內存。

缺點就是很有可能會造成內存的浪費,原因也很明顯,開始分配了一大塊內存,不是全部都用得到的。

針對內存池,這裏有兩個實現,頭一個很簡單,用到了STL的隊列來管理內存池指針,而且如果分配的內存沒有顯示的歸還給內存池的話,即使內存池銷燬的時候,這塊內存也不會被銷燬,就會有內存泄露,當然這個程序還可以改進,另外一個程序是根據《C++應用程序性能優化》中提到的一種方法來實現的,程序見下面:

簡單實現(還有很大的改進餘地):

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   MemPool.h
  3. //  創建者     :   magicTong
  4. //  創建時間    :   2008-10-24 17:50:00
  5. //  功能描述    :  一個簡單的內存池實現
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #ifndef __MEMPOOL_H__
  10. #define __MEMPOOL_H__
  11. // -------------------------------------------------------------------------
  12. #include <queue>
  13. #define  MemoryBlockSize    1024
  14. #define  MemoryBlockNum     20
  15. class KMemPool
  16. {
  17. public:
  18.     // 構造
  19.     explicit KMemPool(int a_memoryBlockNum = MemoryBlockNum, 
  20.                         int a_memoryBlockSize = MemoryBlockSize);
  21.     // 析構
  22.     virtual ~KMemPool();
  23.     // 兩個主要的操作
  24.     int NewMemBuf(char*& a_recvBuff);
  25.     int DelMemBuf(char* a_recvBuff);
  26. private:
  27.     void _initMemPool(int a_memoryBlockNum, int a_memoryBlockSize);
  28.     std::queue<char*> m_memPool;
  29. };
  30. // -------------------------------------------------------------------------
  31. // $Log: $
  32. #endif /* __MEMPOOL_H__ */

實現:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   MemPool.cpp
  3. //  創建者     :   magicTong
  4. //  創建時間    :   2008-10-24 17:50:19
  5. //  功能描述    :   簡單內存池實現
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #include "stdafx.h"
  10. #include "MemPool.h"
  11. // -------------------------------------------------------------------------
  12. // 構造
  13. KMemPool::KMemPool(int a_memoryBlockNum /* = MemoryBlockNum */
  14.                    int a_memoryBlockSize /* = MemoryBlockSize */)
  15. {
  16.     _initMemPool(a_memoryBlockNum, a_memoryBlockSize);
  17. }
  18. // 析構
  19. KMemPool::~KMemPool()
  20. {
  21.     char* l_tempBuff = NULL;
  22.     while(!m_memPool.empty())
  23.     {
  24.         l_tempBuff = m_memPool.front();
  25.         m_memPool.pop();
  26.         if(l_tempBuff )
  27.         {
  28.             // 回收
  29.             delete[] l_tempBuff;
  30.             l_tempBuff = NULL;
  31.         }
  32.     }
  33. }
  34. // -------------------------------------------------------------------------
  35. // 函數       : KMemPool::_initMemPool
  36. // 功能       : 
  37. // 返回值  : void 
  38. // 參數       : int a_memoryBlockNum
  39. // 參數       : int a_memoryBlockSize
  40. // 附註       : 
  41. // -------------------------------------------------------------------------
  42. void KMemPool::_initMemPool(int a_memoryBlockNum, int a_memoryBlockSize)
  43. {
  44.     for(int i = 0; i < a_memoryBlockNum; ++i)
  45.     {
  46.         char* l_tempBuff = new char[a_memoryBlockSize];
  47.         if(l_tempBuff == NULL)
  48.             continue;
  49.         m_memPool.push(l_tempBuff);
  50.     }
  51.     
  52. }
  53. // -------------------------------------------------------------------------
  54. // 函數       : KMemPool::NewMemBuf
  55. // 功能       : 申請一塊內存,如果內存池空了,這個時候應該再像系統申請,並且在
  56. //            類初始化的時候,加一個增量的變量,也可以提供這樣的接口,這裏爲
  57. //            了簡單就沒有這麼做了,只是爲了說明問題而已。
  58. // 返回值  : int 
  59. // 參數       : char*& a_memoryBuff
  60. // 附註       : 如果成功返回0,如果失敗返回-1
  61. // -------------------------------------------------------------------------
  62. int KMemPool::NewMemBuf(char*& a_memoryBuff)
  63. {
  64.     // 如果內存池已空,這個時候正確的做法應該是
  65.     // 重新申請大塊內存
  66.     if (m_memPool.empty())
  67.     {
  68.         _initMemPool(MemoryBlockNum, MemoryBlockSize);
  69.     }
  70.     a_memoryBuff = m_memPool.front();
  71.     m_memPool.pop();
  72.     if(a_memoryBuff == NULL)
  73.         return -1;
  74.     return 0;
  75. }
  76. // -------------------------------------------------------------------------
  77. // 函數       : KMemPool::DelMemBuf
  78. // 功能       : 回收內存,將其放回隊列中
  79. // 返回值  : int 
  80. // 參數       : char* a_memoryBuff
  81. // 附註       : 
  82. // -------------------------------------------------------------------------
  83. int KMemPool::DelMemBuf(char* a_memoryBuff)
  84. {
  85.     m_memPool.push(a_memoryBuff);
  86.     return 0;
  87. }
  88. // -------------------------------------------------------------------------
  89. // $Log: $

根據《C++應用程序性能優化》實現代碼如下:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   MemPoolEx.h
  3. //  創建者     :   magicTong
  4. //  創建時間    :   2008-10-24 17:49:33
  5. //  功能描述    :   
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #ifndef __MEMPOOLEX_H__
  10. #define __MEMPOOLEX_H__
  11. // -------------------------------------------------------------------------
  12. #include <Windows.h>
  13. #define MEMPOOL_ALIGNMENT 4
  14. class KMemBlock  
  15. {
  16. public:
  17.     KMemBlock(USHORT nTypes = 1, USHORT nUnitSize = 0);    
  18.     virtual ~KMemBlock();
  19.     
  20.     void  operator delete(void *p, size_t);
  21.     void * operator new (size_tUSHORT nTypes, USHORT nUnitSize);    
  22.     
  23. public:
  24.     USHORT          nSize;              // 內存塊的大小  每個小塊所佔內存*小塊個數
  25.     USHORT          nFree;              // 空閒塊數
  26.     USHORT          nFirst;             // 第一個空閒塊
  27.     //USHORT          nDummyAlign1;        
  28.     KMemBlock       *pNext;             // 下一個Block
  29.     char            aData[1];           // 數據的初始位置
  30. };
  31. class KMemPoolEx  
  32. {
  33. public:
  34.     KMemPoolEx(USHORT uUnitSize, USHORT uInitSize, USHORT uGrowSize);
  35.     virtual ~KMemPoolEx();
  36.     
  37.     void* Alloc();
  38.     void Free(void* pFree);
  39.     
  40. private:
  41.     void _FreeMemeoryBlock(KMemBlock* pMyBlock);
  42.     
  43.     KMemBlock*      pBlock;         // 第一個block的指針 
  44.     USHORT          nUnitSize;      // 每個小內存塊的字節數
  45.     USHORT          nInitSize;      // 初始的Block的內存塊數目
  46.     USHORT          nGrowSize;      // 增加的Block的內存塊數目
  47. };
  48. // -------------------------------------------------------------------------
  49. // $Log: $
  50. #endif /* __MEMPOOLEX_H__ */

實現部分:

  1. /* -------------------------------------------------------------------------
  2. //  文件名     :   MemPoolEx.cpp
  3. //  創建者     :   magicTong
  4. //  創建時間    :   2008-10-24 17:49:45
  5. //  功能描述    :   
  6. //
  7. //  $Id: $
  8. // -----------------------------------------------------------------------*/
  9. #include "stdafx.h" 
  10. #include "MemPoolEx.h" 
  11. // ------------------------------------------------------------------------- 
  12. // 構造 
  13. KMemBlock::KMemBlock (USHORT nTypes, USHORT nUnitSize)
  14. {
  15.     nFree = nTypes - 1;
  16.     pNext = NULL;
  17.     nSize = nTypes * nUnitSize;
  18.     nFirst = 1;
  19.     char* pData = aData;
  20.     for(USHORT i = 1; i < nTypes; i++)
  21.     {
  22.         *(USHORT *)pData = i;
  23.         pData += nUnitSize;
  24.     }
  25. }
  26. // 析構 
  27. KMemBlock::~KMemBlock()
  28. {
  29. }
  30. // ------------------------------------------------------------------------- 
  31. // 函數       : KMemBlock::operator new 
  32. // 功能       :  
  33. // 返回值  : void *  
  34. // 參數       : size_t 
  35. // 參數       : USHORT nTypes 
  36. // 參數       : USHORT nUnitSize 
  37. // 附註       :  
  38. // ------------------------------------------------------------------------- 
  39. void * KMemBlock::operator new(size_tUSHORT nTypes, USHORT nUnitSize)
  40. {
  41.     return ::operator new (sizeof(KMemBlock) + nTypes * nUnitSize);
  42. }
  43. // ------------------------------------------------------------------------- 
  44. // 函數       : KMemBlock::operator delete 
  45. // 功能       :  
  46. // 返回值  : void   
  47. // 參數       : void *p 
  48. // 參數       : size_t 
  49. // 附註       :  
  50. // ------------------------------------------------------------------------- 
  51. void  KMemBlock::operator delete(void *p, size_t)
  52. {
  53.     ::operator delete (p);
  54. }
  55. // ------------------------------------------------------------------------- 
  56. // 線程池定義 
  57. // ------------------------------------------------------------------------- 
  58. // 構造 
  59. // _uUnitSize 每個小內存塊的字節數 
  60. // _uInitSize 是初始的Block的內存塊數目 
  61. // _uGrowSize 增加的Block的內存塊數目 
  62. KMemPoolEx::KMemPoolEx(USHORT _uUnitSize, USHORT _uInitSize, USHORT _uGrowSize)
  63. {
  64.     pBlock = NULL;
  65.     nInitSize = _uInitSize;
  66.     nGrowSize = _uGrowSize;
  67.     
  68.     if(_uUnitSize <= 2)
  69.         nUnitSize = 2;
  70.     else if(_uUnitSize > 2 && _uUnitSize <= 4)
  71.         nUnitSize = 4;
  72.     else 
  73.     {
  74.         if(_uUnitSize % MEMPOOL_ALIGNMENT == 0)
  75.             nUnitSize = _uUnitSize;
  76.         else
  77.             nUnitSize = (_uUnitSize / MEMPOOL_ALIGNMENT + 1) * MEMPOOL_ALIGNMENT;
  78.     }
  79. }
  80. // 析構 
  81. KMemPoolEx::~KMemPoolEx()
  82. {
  83.     KMemBlock* pMyBlock = pBlock;
  84.     if(pBlock)
  85.         _FreeMemeoryBlock(pMyBlock);
  86. }
  87. // ------------------------------------------------------------------------- 
  88. // 函數       : KMemPool::_FreeMemeoryBlock 
  89. // 功能       : 遞歸釋放內存 
  90. // 返回值  : void  
  91. // 參數       : KMemBlock *pMyBlock 
  92. // 附註       : 其實這個地方沒必要使用遞歸,迭代實現很容易 
  93. // ------------------------------------------------------------------------- 
  94. void KMemPoolEx::_FreeMemeoryBlock(KMemBlock *pMyBlock)
  95. {
  96.     if(pMyBlock->pNext)
  97.         _FreeMemeoryBlock(pMyBlock->pNext);
  98.     delete pMyBlock;
  99. }
  100. // ------------------------------------------------------------------------- 
  101. // 函數       : KMemPoolEx::Alloc 
  102. // 功能       : 申請內存 
  103. // 返回值  : void*  
  104. // 附註       :  
  105. // ------------------------------------------------------------------------- 
  106. void* KMemPoolEx::Alloc()
  107. {
  108.     if(!pBlock)
  109.     {
  110.         // 如果是第一次申請 
  111.         pBlock = new (nInitSize, nUnitSize) KMemBlock(nInitSize, nUnitSize);
  112.         return pBlock->aData;
  113.     }
  114.     // 如果不是第一次申請 
  115.     KMemBlock *pMyBlock = pBlock;
  116.     while(pMyBlock && !pMyBlock->nFree)
  117.         pMyBlock = pMyBlock->pNext;
  118.     //接下來的兩種情況:1.找到有空閒塊的block 2.找不到 
  119.     void *retval;
  120.     // 找到了空閒塊 
  121.     if(pMyBlock)
  122.     {
  123.         pMyBlock->nFree--;
  124.         retval = pMyBlock->aData + nUnitSize * pMyBlock->nFirst;
  125.         pMyBlock->nFirst = *((USHORT*)retval);
  126.         return retval;
  127.     }
  128.     // 沒有找到空閒塊,要重新申請 
  129.     else
  130.     {
  131.         if(!nGrowSize)
  132.             return NULL;
  133.         KMemBlock* newBlock = new (nGrowSize, nUnitSize) KMemBlock(nGrowSize, nUnitSize);
  134.         if(!newBlock)
  135.             return NULL;
  136.         newBlock->pNext = pBlock;
  137.         pBlock = newBlock;
  138.         return (void*)(newBlock->aData);
  139.     }
  140.     
  141.     return NULL;
  142. }
  143. // ------------------------------------------------------------------------- 
  144. // 函數       : KMemPoolEx::Free 
  145. // 功能       : 釋放內存 
  146. // 返回值  : void  
  147. // 參數       : void* pFree 
  148. // 附註       : 釋放內存時,並不真正的歸還給堆,而且是回收到內存池中 
  149. // ------------------------------------------------------------------------- 
  150. void KMemPoolEx::Free(void* pFree)
  151. {
  152.     KMemBlock* pMyBlock = pBlock;
  153.     KMemBlock* pPreBlock = NULL;    //pMyBlock指向Block的前一個Block,用於設置pNext 
  154.     // 如果要求釋放的內存並不是內存池裏面的內存,則直接返回,不予釋放 
  155.     while((ULONG)pFree < (ULONG)pMyBlock->aData || (ULONG)pFree > (ULONG)(pMyBlock->aData + pMyBlock->nSize))
  156.     {
  157.         pPreBlock = pMyBlock;
  158.         pMyBlock = pMyBlock->pNext;
  159.         if(!pMyBlock)
  160.             return;
  161.     }
  162.     // 是內存池裏面分配出去的,回收到內存池,並不真正歸還給堆 
  163.     if(pMyBlock)
  164.     {
  165.         pMyBlock->nFree++;
  166.         *((USHORT*)pFree) = pMyBlock->nFirst;
  167.         pMyBlock->nFirst = (USHORT)(((ULONG)pFree - (ULONG)pMyBlock->aData) / nUnitSize);
  168.         
  169.         if(pMyBlock->nFree * nUnitSize == pMyBlock->nSize)   //如果全是自由塊 
  170.         {
  171.             if(!pMyBlock->pNext)  //如果這是最後一個block,則將其釋放 
  172.             {
  173.                 delete pMyBlock;  //釋放 
  174.                 if(pPreBlock)
  175.                     pPreBlock->pNext = NULL;  //設置上一塊的pNext指向NULL 
  176.                 else
  177.                     pBlock = NULL;
  178.             }
  179.                 
  180.         }
  181.     }
  182. }
  183. // ------------------------------------------------------------------------- 
  184. // $Log: $

數據庫連接池是因爲,初始化一個數據庫連接是非常消耗系統資源的,因此就在程序開始階段進行數據庫的批量連接,然後把這些連接保存下來,等到要使用的時候纔拿出來使用,使用完了再放入連接池中。瞭解不深就不多說了。

 

參考資料:

CSDN博客:許式偉 著 內存池(MemPool)技術詳解 http://blog.csdn.net/xushiweizh/archive/2006/11/22/1402967.aspx

IBM技術文檔:內存池 http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html?ca=drs-cn

Java中數據庫連接池原理機制講解:http://www.68design.net/Development/JSP/20703-1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章