1. 程式人生 > >OpenCV記憶體池管理(一)

OpenCV記憶體池管理(一)

OpenCV提供了一套高效的記憶體管理方案,提升了記憶體申請速率,減少了記憶體碎片,能夠很好的提升程式的穩定性,同時支援執行緒同步。下面是對OpenCV記憶體管理原始碼中alloc.cpp的主要函式fastMalloc()fastFree()的解讀研究。

1、啟用記憶體池分配記憶體

OpenCV3.1中(包括之前的版本),預設是不啟用記憶體池分配的。我的辦法是對原始碼修改後重新編譯。步驟如下:
  1. 在alloc.cpp中新增標頭檔案#include <Windows.h>;
  2. 將巨集CV_USE_SYSTEM_MALLOC改為0;
  3. 將AutoLock在該cpp中的名字替換為其他名字,如TAutoLock。
重新編譯後就可以使用了。

2、原理說明

記憶體池首先分配了一個巨大記憶體塊,大小為1MB,然後在其中劃分為一個個的小塊,每個小塊大小為16KB,每個小塊又可按照給定的記憶體大小分配表劃分為29個型別,將每個小塊按型別進行大小區段均分。申請記憶體時首先判斷該大小的記憶體屬於哪個型別,然後再在某個小塊上進行分配工作。

3、基本結構及引數定義說明

  • 型別表binSizeTab
static const int binSizeTab[MAX_BIN+1] =
{ 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 128, 160, 192, 256, 320, 384, 480, 544, 672, 768,
896, 1056, 1328, 1600, 2688, 4048, 5408, 8128, 16256 };//29種類型
記憶體分配查詢表MallocTables struct MallocTables
{
uchar binIdx[MAX_BLOCK_SIZE/8+1];//對要分配的記憶體大小,能夠以O(1)的時間複雜度找到對應的塊型別大小
}
  • 最基本的記憶體塊Block
struct Block{
    size_t signature;//標記,表明該記憶體塊是該記憶體池分配的
    Block* prev; //上一個Block,不同情況下的意義不同
    Block* next; //下一個Block,不同情況下的意義不同
    Node* privateFreeList; //當前塊的私有自由區段地址連結串列
    Node* publicFreeList; //
    uchar* bumpPtr; //當前小塊中第一個可用區段地址,該指標只能往endPtr方向偏移累加
    uchar* endPtr; //當前小塊中最後一個可用區段的尾地址
    uchar* data; //塊中偏移頭部結構後的資料區
    ThreadData* threadData; //執行緒資料指標
    int objSize; //當前塊型別的大小,對應binSizeTab中的數值
    int binIdx; //當前塊型別在記憶體分配查詢表MallocTables中的下標
    int allocated; //該區塊已分配的區段個數
    int almostEmptyThreshold; //閾值判斷,與是否將該區塊作為可用區塊的判斷有關
    CriticalSection cs; //臨界區
}
  • 巨大記憶體塊BigBlock
struct BigBlock
{
    BigBlock* next;//下一個巨大記憶體塊
    Block* first; //巨大記憶體塊中第一個區塊地址
    int nblocks; //巨大記憶體塊中區塊個數
}
  • 記憶體池基本結構BigBlock
struct BlockPool
{
    CriticalSection cs;//臨界區
    Block* freeBlocks; //指向記憶體池中自由塊連結串列
    BigBlock* pool;//指向第一個巨大記憶體塊地址
    int bigBlockSize;//巨大記憶體塊的大小
    int blocksPerBigBlock;//未使用
}
  • 執行緒資料結構ThreadData
struct ThreadData
{
Block* bins[MAX_BIN+1][3];//用START、FREE控制每個區段的區塊雙向連結串列
static DWORD tlsKey;
}

4、記憶體池結構圖