OpenCV内存池管理(一)

OpenCV提供了一套高效的内存管理方案,提升了内存申请速率,减少了内存碎片,能够很好的提升程序的稳定性,同时支持线程同步。下面是对OpenCV内存管理源码中alloc.cpp的主要函数fastMalloc()fastFree()的解读研究。

1、启用内存池分配内存

OpenCV3.1中(包括之前的版本),默认是不启用内存池分配的。我的办法是对源码修改后重新编译。步骤如下:
  1. 在alloc.cpp中添加头文件#include ;
  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、内存池结构图


OpenCV内存池管理(一)_第1张图片



你可能感兴趣的:(数据结构与算法,c/c++,图像处理)