[原创]小结:opencv中碰到的cvGetSubRect内存泄漏问题(初学者笔记)
2011-05-08 20:26
351 查看
近日在写一段opencv程序,使用cvGetSubRect()函数时碰到了内存泄漏问题(参见:Justin http://blog.csdn.net/Justin4wd/archive/2008/06/26/2588243.aspx)。本人菜鸟,对这个所谓的内存泄漏问题一知半解,碰到了才想到去弄明白。
首先google + wikipedia,它们告诉我所谓内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。
那么,怎样才会“在释放该内存前就失去了对该内存的控制呢”?小菜立刻写了这样一段c++代码:
//产生内存泄漏的一段代码
int main()
{
char *str = NULL;
for (int i = 0; i < 1000; i++)
{
str = new char[100000]; //只有new,没有delete,将产生内存泄漏
Sleep(100); //延时100ms,可以打开任务管理器观测内存变化
}
return 0;
}
果然,程序运行后,打开任务管理器,发现内存使用在狂飙上升。 对照上面的定义,分析:第一次new之后,将分配的地址赋给了指针str,此时,我们对改内存空间是有控制的的;第二次new之后,又分配了一块同样大小 的内存(注意此时第一次分配的内存并未释放),当指针str重新赋值后,此时str指向第二次分配的内存,我们就丢失对第一次分配的内存的控制了,内存泄 漏就产生了。程序不断执行下去,没有得到释放的内存片段越来越多,直到内存耗尽程序崩溃。
因此,动态分配的内存在不适用时一定要释放。比如上面的代码,可改为:
int main()
{
char *str = NULL;
for (int i = 0; i < 1000; i++)
{
str = new char[100000]; //只有new,没有delete,将产生内存泄漏
Sleep(100); //延时100ms,可以打开任务管理器观测内存变化
delete []str; //释放内存
}
return 0;
}
好了,到此,小菜对内存泄漏总算是有个直观的印象了。下面琢磨下cvGetSubRect()函数是怎样产生内存泄漏的。函数原型:
CV_IMPL CvMat*
cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect )
小菜原来的用法:
...
CvMat *firstFrameSub = cvCreateMat( rows, cols, CV_8UC1 ); //创建一个rows*cols 的8-bit 无符号单通道矩阵
cvGetSubRect(src, firstFrameSub, rect); //此处产生内存泄漏!
...
进入cvGetSubRect定义代码:
CV_IMPL CvMat*
cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect )
{
CvMat* res = 0;
CV_FUNCNAME( "cvGetRect" );
__BEGIN__;
CvMat stub, *mat = (CvMat*)arr;
if( !CV_IS_MAT( mat ))
CV_CALL( mat = cvGetMat( mat, &stub ));
if( !submat )
CV_ERROR( CV_StsNullPtr, "" );
if( (rect.x|rect.y|rect.width|rect.height) < 0 )
CV_ERROR( CV_StsBadSize, "" );
if( rect.x + rect.width > mat->cols ||
rect.y + rect.height > mat->rows )
CV_ERROR( CV_StsBadSize, "" );
{
//从此处可以看出,如果submat已经分配有内存空间,那么,此处将产生内存泄漏,切记传递submat时,一定要穿一个没有分配内存的指针。
submat->data.ptr = mat->data.ptr + (size_t)rect.y*mat->step +
rect.x*CV_ELEM_SIZE(mat->type);
submat->step = mat->step & (rect.height > 1 ? -1 : 0);
submat->type = (mat->type & (rect.width < mat->cols ? ~CV_MAT_CONT_FLAG : -1)) |
(submat->step == 0 ? CV_MAT_CONT_FLAG : 0);
submat->rows = rect.height;
submat->cols = rect.width;
submat->refcount = 0;
res = submat;
}
__END__;
return res;
}
因此,使用cvGetSubRect时候要非常注意,它的第二个参数不能预先分配内存。这和大部分的opencv函数不一样。
参考资料:
http://blog.csdn.net/Justin4wd/archive/2008/06/26/2588243.aspx
首先google + wikipedia,它们告诉我所谓内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。
那么,怎样才会“在释放该内存前就失去了对该内存的控制呢”?小菜立刻写了这样一段c++代码:
//产生内存泄漏的一段代码
int main()
{
char *str = NULL;
for (int i = 0; i < 1000; i++)
{
str = new char[100000]; //只有new,没有delete,将产生内存泄漏
Sleep(100); //延时100ms,可以打开任务管理器观测内存变化
}
return 0;
}
果然,程序运行后,打开任务管理器,发现内存使用在狂飙上升。 对照上面的定义,分析:第一次new之后,将分配的地址赋给了指针str,此时,我们对改内存空间是有控制的的;第二次new之后,又分配了一块同样大小 的内存(注意此时第一次分配的内存并未释放),当指针str重新赋值后,此时str指向第二次分配的内存,我们就丢失对第一次分配的内存的控制了,内存泄 漏就产生了。程序不断执行下去,没有得到释放的内存片段越来越多,直到内存耗尽程序崩溃。
因此,动态分配的内存在不适用时一定要释放。比如上面的代码,可改为:
int main()
{
char *str = NULL;
for (int i = 0; i < 1000; i++)
{
str = new char[100000]; //只有new,没有delete,将产生内存泄漏
Sleep(100); //延时100ms,可以打开任务管理器观测内存变化
delete []str; //释放内存
}
return 0;
}
好了,到此,小菜对内存泄漏总算是有个直观的印象了。下面琢磨下cvGetSubRect()函数是怎样产生内存泄漏的。函数原型:
CV_IMPL CvMat*
cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect )
小菜原来的用法:
...
CvMat *firstFrameSub = cvCreateMat( rows, cols, CV_8UC1 ); //创建一个rows*cols 的8-bit 无符号单通道矩阵
cvGetSubRect(src, firstFrameSub, rect); //此处产生内存泄漏!
...
进入cvGetSubRect定义代码:
CV_IMPL CvMat*
cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect )
{
CvMat* res = 0;
CV_FUNCNAME( "cvGetRect" );
__BEGIN__;
CvMat stub, *mat = (CvMat*)arr;
if( !CV_IS_MAT( mat ))
CV_CALL( mat = cvGetMat( mat, &stub ));
if( !submat )
CV_ERROR( CV_StsNullPtr, "" );
if( (rect.x|rect.y|rect.width|rect.height) < 0 )
CV_ERROR( CV_StsBadSize, "" );
if( rect.x + rect.width > mat->cols ||
rect.y + rect.height > mat->rows )
CV_ERROR( CV_StsBadSize, "" );
{
//从此处可以看出,如果submat已经分配有内存空间,那么,此处将产生内存泄漏,切记传递submat时,一定要穿一个没有分配内存的指针。
submat->data.ptr = mat->data.ptr + (size_t)rect.y*mat->step +
rect.x*CV_ELEM_SIZE(mat->type);
submat->step = mat->step & (rect.height > 1 ? -1 : 0);
submat->type = (mat->type & (rect.width < mat->cols ? ~CV_MAT_CONT_FLAG : -1)) |
(submat->step == 0 ? CV_MAT_CONT_FLAG : 0);
submat->rows = rect.height;
submat->cols = rect.width;
submat->refcount = 0;
res = submat;
}
__END__;
return res;
}
因此,使用cvGetSubRect时候要非常注意,它的第二个参数不能预先分配内存。这和大部分的opencv函数不一样。
参考资料:
http://blog.csdn.net/Justin4wd/archive/2008/06/26/2588243.aspx
相关文章推荐
- [原创]小结:opencv中碰到的cvGetSubRect内存泄漏问题(初学者笔记)
- 《学习opencv》笔记——矩阵和图像操作——cvGertDims,cvGetDimSize,cvGetRow,cvGetRow,cvGetSize and cvGetSubRect
- apt-get安装的OpenCV库中cvFindChessboardCorners函数的问题
- [OpenCV] cvGetSubRect的使用
- OpenCV笔记1---报错 cv::Exception,更改路径后问题解决。
- [原创]java WEB学习笔记19:初识MVC 设计模式:查询,删除 练习(理解思想),小结 ,问题
- OpenCv学习笔记(二)—cv::Mat学习
- [原创]Spring: A Developer's Notebook笔记和小结(15)
- 解决Ubuntu环境下ROS Kinetic中的cv_bridge和自己安装OpenCV 2.4.xx兼容性笔记
- 关于opencv里,imshow和cvShowImage之后不显示的问题
- C++初学者笔记:std::thread,子线程阻塞主线程的问题
- 笔记-广达服务器时碰到的一些问题的
- opencv学习笔记1:CV_MAT_ELEM_PTR与CV_MAT_ELEM的用法
- OpenCv学习笔记(二)--Mat矩阵(图像容器)的创建及CV_8UC1,CV_8UC2等参数详解
- cv_bridge依赖opencv版本的问题
- PHP初学者最感迷茫的问题小结
- Intent工作笔记,getIntent() 为空的问题
- Android笔记 Application对象的使用-数据传递以及内存泄漏问题
- cvGetCol与cvGetCols 获取列 cvGetSubRect获取图像的矩形区域
- 【原创】SharePoint Document library List Check out 文档时碰到的问题解决