上文介绍了C/C++编码中内存泄露的问题,不过经过本人测试,好像对用opencv工具包进行编码中的内存泄露并不起作用。CrtSetDbgFlag函数应该针对new/malloc这种方式分配内存的,而opencv的很多函数把内存分配封装了,直接返回一个指针(e.g. cvCreateImage返回IplImage指针),因而并不能检测出opencv编码的内存泄露.(这一段不知道说得对不对,还有待查证:0) ).针对这个问题,网上有一个比较好的解决方法,就直接来过来用了。它是一个针对opencv的内存泄露检测的类,实现如下:

 

//头文件
#ifndef OPENCV_MEM_TRACKER_H
#define OPENCV_MEM_TRACKER_H

#include <stdio.h>
#include <vector>

// 内存泄漏追踪类
class MemTracker
{
public:
MemTracker(void);
~MemTracker(void);

private:

// 登记分配/释放的内存
void regAlloc(void *ptr, size_t size);
void regFree(void *ptr);

// 输出泄漏的内存
int output(FILE* fp=stderr);

private:

// 分配内存
static void* alloc_func(size_t size, void *userdata);

// 释放内存
static int free_func(void *ptr, void *userdata);

private:

struct Ptr
{
void *ptr; // 内存地址
size_t size; // 内存大小
int id;

Ptr(void *ptr, size_t size, int id)
{
this->ptr = ptr;
this->size = size;
this->id = id;
}
};

// 记录当前使用中的内存
std::vector<Ptr> m_memTracker;

// alloc_func对应的编号
int m_id;
};

#endif // OPENCV_MEM_TRACKER_H
 
//cpp文件
#include "MemTracker.h"

#include <assert.h>
#include <cv.h>

MemTracker::MemTracker(void)
{
m_id = 0;

// 注册管理函数
cvSetMemoryManager(alloc_func, free_func, (void*)this);
}

MemTracker::~MemTracker(void)
{
// 取消管理函数

cvSetMemoryManager(NULL, NULL, NULL);

// 输出结果

this->output();
}

// 登记分配/释放的内存

void MemTracker::regAlloc(void *ptr, size_t size)
{
// 每次记录一个新的m_id
m_memTracker.push_back(Ptr(ptr, size, m_id++));
}

void MemTracker::regFree(void *ptr)
{
int i;
for(i = 0; i < m_memTracker.size(); ++i)
{
// 删除记录
if(m_memTracker[i].ptr == ptr)
{
m_memTracker[i] = m_memTracker[m_memTracker.size()-1];
m_memTracker.pop_back();
return;
}
}
}

// 输出泄漏的内存

int MemTracker::output(FILE* fp)
{
int n = m_memTracker.size();
int i;

for(i = 0; i < n; ++i)
{
fprintf(fp, "%d: %p, %u\n", m_memTracker[i].id, m_memTracker[i].ptr, m_memTracker[i].size);
}

return n;
}

// 分配内存

void* MemTracker::alloc_func(size_t size, void *userdata)
{
assert(size > 0 && userdata != NULL);

// 分配内存

void *ptr = malloc(size);
if(!ptr) return NULL;

// 登记
MemTracker *tracker = (MemTracker*)userdata;
tracker->regAlloc(ptr, size);

//

return ptr;
}

// 释放内存

int MemTracker::free_func(void *ptr, void *userdata)
{
assert(ptr != NULL && userdata != NULL);

// 释放内存

free(ptr);

// 登记

MemTracker *tracker = (MemTracker*)userdata;
tracker->regFree(ptr);

// CV_OK == 0

return 0;
}
 
//测试程序
int main()
{
//实例化
MemTracker tracker;

//加载图片,注意它没有被release掉
IplImage * pImg = cvLoadImage("E:\\test photos3\\SDC10126.JPG", 1);

return 0;
}


使用的时候,MemTracker会跟每一个指针分配一个id,并记录它的分配与释放情况,对没有释放的内存将会被打印出来,包括此指针的id号, 指针的16进制值,以及所指内存的大小。按f5进行调试,根据id号找到泄露内存代码的具体位置,添加释放代码。