在STL容器中存储OpenCV Mat对象时避免内存泄漏

时间:2013-11-01 20:39:23

标签: c++ opencv memory-leaks

我正在使用OpenCV,我想在矢量中存储许多图像(Mat个对象)。我已经按照以下方式声明了向量来存储指向Mat个对象的指针。

std::vector<Mat*> images;

使用Mat关键字创建new个对象,然后将其添加到向量中。

Mat *img = new Mat(height, width, CV_8UC3);
// set the values for the pixels here
images.push_back(img);

我如何确保释放Mat对象占用的内存以避免内存泄漏?

我现在正在做的是以下内容:

Mat *im = images.at(index);
// process and display image here
delete(im);

Valgrind正在参考创建的Mat对象来修复可能的内存泄漏。我错过了什么吗?

修改

确定。显然,最好避免使用Mat指针并使用Mat动态分配new。我修改了我的代码以改为使用std::vector<Mat>。但是,我仍然看到Mat分配的一些块可能在Valgrind报告中丢失了。我还注意到程序运行时内存使用量稳步增加。

让我澄清一下我在做什么。我正在函数中创建图像并将它们放在缓冲区中(内部使用std::deque)。然后,该缓冲区由另一个函数访问以检索和成像,并将其传递给执行处理和渲染的另一个函数。

class Render {
   public:
      void setImage(Mat& img) {
         this->image = img;
      }

      void render() {
         // process image and render here
      }
   private:
      Mat image;
}

从缓冲区连续提取图像并呈现它们的线程。

void* process(void *opaque) {

   ImageProcessor *imgProc = (ImageProcessor*) opaque;
   Mat img;


   while (imgProc->isRunning) {
      // get an image from the buffer
      imgProc->buffer->getFront(img);

      // set the image
      imgProc->renderer->setImage(img);

      // process and render
      imgProc->renderer->render();
   }

}

现在,所有内容都作为对象引用传递(即Mat&)。我假设从缓冲区获取图像并将其传递给渲染函数后,对该对象的唯一引用将在该函数中。因此,当我得到另一个图像时,将不再有对该对象的引用,它将被销毁。但Valgrind给了我以下内容:

25,952,564 bytes in 11 blocks are possibly lost in loss record 14,852 of 14,853
  in ImageProcessor::generateImage() in ImageProcessor.cpp:393
  1: malloc in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so
  2: cv::fastMalloc(unsigned long) in /usr/local/lib/libopencv_core.so.2.4.2
  3: cv::Mat::create(int, int const*, int) in /usr/local/lib/libopencv_core.so.2.4.2
  4: cv::Mat::create(int, int, int) in /usr/local/include/opencv2/core/mat.hpp:353
  5: cv::Mat::Mat(int, int, int) in /usr/local/include/opencv2/core/mat.hpp:75
  ...

这是generateImage()

void generateImage() {
   Mat img(h, w, CV_8UC3); 
   // set values of pixels here
   this->buffer->pushBack(img);
}

2 个答案:

答案 0 :(得分:1)

这似乎是共享指针的一个很好的用例。智能指针背后的基本思想是它的行为类似于引用计数的常规指针。当没有别的东西可以引用它时,它会自动释放自己。

您在示例中使用它们的方式是

std::vector<std::shared_ptr<Mat> > images;
std::shared_ptr<Mat> mat_ptr (new Mat(height, width, CV_8UC3));
images.push_back(mat_ptr);

Here是一个方便的教程,有关共享指针的更多信息。如果我误解了您的问题/问题,请随时跟进。

答案 1 :(得分:1)

如果您小心实际删除对象,则没有内存泄漏。话虽这么说,有一些方法可以在不太容易出现人为错误的向量中存储指针(即你忘记在应用程序的某些角落删除对象)。

如果您可以使用C ++ 11,那么我建议使用std::shared_ptr而不是原始指针。这将确保在不再使用Mat对象的任何代码时(自动)删除内存。

还有一个优点,除了必须更改指针的类型之外,您不需要进行任何其他修改。通常的ptr->member*ptr表达式也适用于std::shared_ptr

这里有一些documentation on std::shared_ptr。此外,根据您的具体需求,您可能还需要查看std::reference_wrapper


编辑:由于C ++ 11不是一个选项,您可以尝试boost::shared_ptr - 标准std::shared_ptr基于Boost。如果Boost也不是一个选项,你可以实现自己的共享指针,这不是很难。

您的计划规模是值得考虑的事情。如果您的应用程序相当小,并且您几乎没有机会忘记可能导致内存泄漏的一些极端情况,那么所有这些都可能过度工程化。如果只是“手动”删除对象,则会考虑这样做。