zoukankan      html  css  js  c++  java
  • cvLoadImage,cvCloneImage的内存泄露问题

    本文转自:

    http://hi.baidu.com/%C3%A8%D1%DB%D3%E3/blog/item/9d947e1b2b05555742a9adfd.html/cmtid/9872c2260129923cc9955905

        针对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(),来对图像赋值。这样最后释放的是图像指针所指的地址区域。这两种方法都不会出现内存泄露的问题了。

  • 相关阅读:
    防火墙透明模式
    HP管理工具System Management Homepage安装配置
    kbmmw 中JSON 中使用SQL 查询
    kbmmw 中JSON 操作入门
    第一个kbmmw for Linux 服务器
    kbmmw 5.02发布
    kbmmw 5.01 发布
    使用delphi 10.2 开发linux 上的Daemon
    使用unidac 在linux 上无驱动直接访问MS SQL SERVER
    使用delphi 10.2 开发linux 上的webservice
  • 原文地址:https://www.cnblogs.com/xingrun/p/3392687.html
Copyright © 2011-2022 走看看