OpenCV記憶體池管理(一)
阿新 • • 發佈:2019-01-22
OpenCV提供了一套高效的記憶體管理方案,提升了記憶體申請速率,減少了記憶體碎片,能夠很好的提升程式的穩定性,同時支援執行緒同步。下面是對OpenCV記憶體管理原始碼中alloc.cpp的主要函式fastMalloc()和fastFree()的解讀研究。
1、啟用記憶體池分配記憶體
OpenCV3.1中(包括之前的版本),預設是不啟用記憶體池分配的。我的辦法是對原始碼修改後重新編譯。步驟如下:- 在alloc.cpp中新增標頭檔案#include <Windows.h>;
- 將巨集CV_USE_SYSTEM_MALLOC改為0;
- 將AutoLock在該cpp中的名字替換為其他名字,如TAutoLock。
2、原理說明
記憶體池首先分配了一個巨大記憶體塊,大小為1MB,然後在其中劃分為一個個的小塊,每個小塊大小為16KB,每個小塊又可按照給定的記憶體大小分配表劃分為29個型別,將每個小塊按型別進行大小區段均分。申請記憶體時首先判斷該大小的記憶體屬於哪個型別,然後再在某個小塊上進行分配工作。3、基本結構及引數定義說明
- 型別表binSizeTab
記憶體分配查詢表MallocTables struct MallocTablesstatic 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種類型
{
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、記憶體池結構圖