cvLoadImage,cvCloneImage的内存泄露问题
本文转自:
针对openCV中,隐蔽的内存泄露,大家需要重视,拯救为数不多的内存,拯救应用程序的速度
在做项目的过程中,使用OpenCV经常会出现一些内存泄露问题,自己编写的程序出现问题还情有可原,但若是库函数调用和使用时出现,却很令我恼火。花了好长时间和实践的经验告诉我应该客服它。下面把一些检测出的问题进行化解。(可能是水平不够,这些函数使用不当,望高手指点)
cvLoadImage函数:
可能大家还觉察不出来,但我深有体会,在程序中这个函数使用一次两次感觉不来,但在处理序列图像循环调用这个函数时,内存泄露的可能让你目瞪口呆!即使你在最后使用cvReleaseImage(&pImg);进行了释放,实验证明:视乎不能成功释放。
解决方法:
使用CvvImage类代替。并且使用CvvImage类的Load函数。
使用过程大概如下:
//变量定义:
CvvImage pSrcImg;
IplImag *pSrcImgCopy ;//使用IplImag变量做个拷贝。毕竟IplImag 类处理方便。
//获取图像:
pSrcImg.Load(str);//str为Cstring类型的图像文件名
pSrcImgCopy = pSrcImg.GetImage();//拷贝出pSrcImg的图像数据。
//释放内存
pSrcImg变量不需要每次释放,因为每次Load时是覆盖以前的内存区域。pSrcImgCopy 同样。
不过在程序结束时要释放,以免产生内存泄露或者别人以为你忘了。
cvReleaseImage(&pSrcImgCopy );
pSrcImg.Destroy();
不过要正确释放pSrcImgCopy 时,声明时必须create下:
pSrcImgCopy = cvCreateImage(cvSize(IMGWIDHT,IMGHEIGHT),IPL_DEPTH_8U, 3);
//IMGWIDHT,IMGHEIGHT为图像宽和高。
cvCloneImage函数:
这个函数也会出现内存泄露!虽然可以释放,但程序复杂不知道在那里释放,因为它每次拷贝是制作图像的完整拷贝包括头、ROI和数据。不会覆盖以前的内容。每次使用时编译器会分配内存空间。一个752*480大小的图像,每次泄露的内存大约为1M。
解决方法:
使用cvCopy函数代替。
cvCopy(pSrcImg,pImg,NULL);//代替 pImg = cvCloneImage(pSrcImg);
pImg初始化时必须分配空间,否则上述函数不能执行。
pImg = cvCreateImage(cvSize(IMGWIDHT,IMGHEIGHT),IPL_DEPTH_8U, 3);
最近一直在用opencv编写算法程序,但是cvCloneImage、cvCopyImage和cvCloneMat、cvCopyMat这几个函数让我痛苦了好一阵子,程序代码没有任何问题,但是就是得不到结果,在子函数中返回值根本不是我想要的,由于代码挺庞大的,一直没找到问题出在哪里,于是设置一个个断点,通过步步调试,终于发现问题出在了cvCloneImage、cvCopyImage和cvCloneMat、cvCopyMat这几个函数的误用,cvCloneImage与cvCloneMat是在赋值的同时会开辟一个新的空间给定义的变量,cvCopyImage与cvCopyMat只复制值,并不会分配一个空间给赋值对象,因此cvCloneImage与cvCloneMat只适合用于变量开始定义,千万不要用在算法处理中间,否则会产生一个新的地址空间,会将赋值对象的指针地址改变,这样会导致整个程序有不可预测的错误发生,最明显的就是你本来想把子函数中的新变量值送回上一层函数,但是由于指针的指向已经改变,所以返回后的值并不会改变。在程序中间进行复制时候建议使用cvCopyImage与cvCopyMat。
因此当使用opencv函数时候,不同函数实现同一个功能,但是一定要注意他们之间的区别,不然会让你很痛苦,寻找这种错误真的很烦人。
http://benson.is-programmer.com/posts/21042.html
戏剧性阶段一:问题的出现
最近在使用opencv的时候,发现在图像函数部分,opencv的内存管理存在一定问题。在使用IplImage的图像cvcloneImage()后,调用cvReleaseImage()时,内存并不能全部释放。在实时视频处理程序中,伴随程序运行,很容易造成系统内存消耗殆尽。
举例来说,看下面的一个最简单代码:
#include"cv.h"
#include"highgui.h"
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cxcore.lib")
int _tmain(int argc, _TCHAR* argv[])
{
CvCapture* capture = cvCreateCameraCapture(0);
IplImage* frame;
cvNamedWindow("ExampleShow",CV_WINDOW_AUTOSIZE);
while(1)
{
frame = cvQueryFrame(capture);
if(!frame)
break;
cvShowImage("ExampleShow",frame);
char c = cvWaitKey(33);
if(c == 27)
break;
}
cvReleaseCapture(&capture);
cvDestroyWindow("ExampleShow");
return 0;
}
运行程序,此时,打开资源管理器,可以看到其所占的“内存使用”一直保持稳定。而如果,简单修改下上面的程序,改变如下:
#include"cv.h"
#include"highgui.h"
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cxcore.lib")
int _tmain(int argc, _TCHAR* argv[])
{
CvCapture* capture = cvCreateCameraCapture(0);
IplImage* frame;
IplImage* clImage;
cvNamedWindow("ExampleShow",CV_WINDOW_AUTOSIZE);
cvNamedWindow("Example_Clone",CV_WINDOW_AUTOSIZE);
while(1)
{
frame = cvQueryFrame(capture);
if(!frame)
break;
cvShowImage("ExampleShow",frame);
clImage = cvCreateImage(cvSize(frame->width,frame->height),frame->depth,frame->nChannels);
clImage = cvCloneImage(frame);
cvShowImage("Example_Clone",clImage);
char c = cvWaitKey(33);
if(c == 27)
break;
cvReleaseImage(&clImage);
}
cvReleaseCapture(&capture);
cvDestroyWindow("ExampleShow");
cvDestroyWindow("Example_Clone");
return 0;
}
同样,运行程序,打开资源管理器,可以看到“内存使用”中,该程序的内存使用量在不断增加。虽然,程序中对拷贝的图像进行了释放,但是,事实上,却没有看到多少效果!
虽然发现了这个问题,也在网络上看到相关的这个问题的讨论,试验了几种方法,发现并不work。在此提出问题,继续探索吧。
戏剧性阶段二:“改良方法”的出现
在网络上看到,除了cvCloneImage()还有cvLoadImage()也有内存泄露问题。最终的有效解决办法是使用cvCopy()来替换代码中的cvCloneImage(),这时候,不会出现内存不断递增的情况。而cvLoadImage()可以CvvImage类的图像装载函数,然后拷贝到目标图像即可。
戏剧性三:真正原因的捕获和分析
内存无法释放的原因分析:
今天偶然想起,在观察上面的代码时,发现在其中存在一句:clImage = cvCreateImage(cvSize(frame->width,frame->height),frame->depth,frame->nChannels);
这句是向内存申请一片空间,用于存放目的图像的空间。造成内存泄露的真正原因是这句。在使用cvCloneImage()的时候,其实是对源图像指针所指向的图像头、数据、ROI等进行了一个完全的拷贝,放在一个新的内存区域,函数结果使得目标图像指向新的内存,而原来用cvCreateImage()所分配的区域没有被正确释放,成为一片“悬挂地址区域”。在后面调用cvReleaseImage()的时候,释放的是后面其所指向的区域。
因此,要避免这种情况的出现,一种方法是:可以在cvCloneImage()前,先调用cvReleaseImage()来释放之前分配的地址区域。然后执行克隆函数cvCloneImage()操作。也可以在前面不分配空间,直接调用克隆操作。另外一种方法,如果使用cvCopy()函数操作,由于该函数并不会对图像指针分配空间,所以需要先自己用cvCreateImage()分配一段区域,然后调用拷贝函数cvCopy(),来对图像赋值。这样最后释放的是图像指针所指的地址区域。这两种方法都不会出现内存泄露的问题了。
cvLoadImage,cvCloneImage的内存泄露问题的更多相关文章
- java: web应用中不经意的内存泄露
前面有一篇讲解如何在spring mvc web应用中一启动就执行某些逻辑,今天无意发现如果使用不当,很容易引起内存泄露,测试代码如下: 1.定义一个类App package com.cnblogs. ...
- 查看w3wp进程占用的内存及.NET内存泄露,死锁分析
一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- 基于HTML5的WebGL应用内存泄露分析
上篇(http://www.hightopo.com/blog/194.html)我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动, ...
- android:布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!
1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayo ...
- js内存泄露的几种情况详细探讨
内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束.在C++中,因为是手动管理内存,内存泄露是经常出现的事情.而现在流行的C#和Java等语言采用了自动垃圾回收方法管理内存,正常使 ...
- 使用Xcode7的Instruments检测解决iOS内存泄露
文/笨笨的糯糯(简书作者)原文链接:http://www.jianshu.com/p/0837331875f0著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 作为一名iOS开发攻城狮, ...
- 使用Visual Leak Detector for Visual C++ 捕捉内存泄露
什么是内存泄漏? 内存泄漏(memory leak),指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段 ...
- java内存溢出和内存泄露
虽然jvm可以通过GC自动回收无用的内存,但是代码不好的话仍然存在内存溢出的风险. 最近在网上搜集了一些资料,现整理如下: —————————————————————————————————————— ...
随机推荐
- 小程序rpx
rpx是微信小程序解决自适应屏幕尺寸的尺寸单位.微信小程序规定屏幕的宽度是750rpx, 微信小程序也支持rem尺寸单位,rem规定屏幕的宽度是20rem vw vh适配 vw和vh是css3中的新单 ...
- 利用Dockerfile文件创建带有sshd服务的centos镜像
利用Dockerfile文件创建带有sshd服务的centos镜像 标签:dockerfile 1.安装docker并启动docker,不在赘述 2.创建使用Dockerfile安装sshd服务的目录 ...
- AngularJS系统学习之$watch(监控)
在scope的内置的所有函数中,用的最多的可能就是$watch函数了, 当你的数据模型中某一部分发生变化时,$watch函数可以向你发出通知. 你可以监控单个对象的属性,亦可以监控需要经过计算的结果( ...
- hibernate Criteria中or和and的用法
/s筛选去除无效数据 /* detachedCriteria.add( Restrictions.or( Restrictions.like("chanpin", &qu ...
- Mina学习之---mina整体流程介绍
现在公司使用的NIO框架一直时候Mina,当然这也的框架还有Netty.虽然一直在用,但只是简单的停留在业务层面,最近面试的时候有问Mina相关的东西.在之前的博客中已经对BIO,NIO,AIO这三种 ...
- Asset Catalog Help (十一)---Removing Images and Sets
Removing Images and Sets Optimize the size of an asset catalog by removing unused images or sets. 通过 ...
- 1.13-1.14 Hive Action
一.Hive Action 1.创建文件 [root@hadoop-senior oozie-apps]# pwd /opt/cdh-5.3.6/oozie-4.0.0-cdh5.3.6/oozie- ...
- 1.1-1.4 hadoop调度框架和oozie概述
一.hadoop调度框架 Linux Crontab Azkaban https://azkaban.github.io/ Oozie http://oozie.apache.org/ Zeus(阿里 ...
- PHP中正则表达式学习及应用(三)
正则表达式中的“模式修正符” 1.运算顺序 2.模式修正符 i 正则内容在匹配时候不区分大小写(默认是区分的) 例如: <?php $mode="/[a-z]/i"; ...
- CodeForces 496D Tennis Game (暴力枚举)
题意:进行若干场比赛,每次比赛两人对决,赢的人得到1分,输的人不得分,先得到t分的人获胜,开始下场比赛,某个人率先赢下s场比赛时, 游戏结束.现在给出n次对决的记录,问可能的s和t有多少种,并按s递增 ...