简体   繁体   中英

Avoiding memory leaks when storing OpenCV Mat objects in STL containers

I'm using OpenCV and I want to store a number of images ( Mat objects) in a vector. I have declared the vector as follows to store pointers to Mat objects.

std::vector<Mat*> images;

The Mat objects are created using the new keyword, and then added to the vector.

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

How would I go about making sure that I free the memory occupied by the Mat objects to avoid memory leaks?

What I'm doing right now is the following:

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

Valgrind is reporing a possible memory leak with reference to the created Mat objects. Am I missing something?

Edit:

Ok. Apparently it is better to avoid using Mat pointers and dynamically allocating Mat using new . I have modified my code to use std::vector<Mat> instead. However, I still see some blocks that were allocated by Mat possibly lost in the Valgrind report. I also notice that memory usage steadily increases while the program is running.

Let me clarify what I'm doing. I'm creating images in a function and placing them in a buffer (internally using a std::deque ). This buffer is then accessed by another function to retrieve and image and pass it to another function which performs processing and rendering.

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

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

Thread that continuously fetches images from buffer and renders them.

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();
   }

}

Now, everything is passed as object references (ie Mat& ). I assume that after getting an image from the buffer and passing it to the rendering function, the only reference to that object will be in that function. Therefore, when I get another image, there will no longer be a reference to that object and it will be destroyed. But Valgrind gives me the following:

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
  ...

And here is generateImage() :

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

This seems like a great use case for shared pointers. The basic idea behind a smart pointer is that it behaves like a reference counted regular pointer. When nothing else holds a reference to it, it automatically free-s itself.

The way you'd use them in your example would be

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 'sa handy tutorial for more about shared pointers. If I misunderstood something about your question/problem, feel free to follow up below.

If you are careful to actually delete the objects, then there are no memory leaks. That being said, there are ways to store pointers in vectors that are less prone to human errors (ie you forgetting to delete the objects in some corner case of your application).

If you can use C++11 then I'd recommend using std::shared_ptr instead of raw pointers. This will ensure that the memory is deleted (automatically) when there no longer is any code that uses your Mat object.

There's also the advantage that besides having to change the type of the pointer there aren't any other modifications you have to do. The usual ptr->member and *ptr expressions are valid for std::shared_ptr as well.

Here's some documentation on std::shared_ptr . Also, depending on you specific needs, you might want to look into std::reference_wrapper as well.


Edit: Since C++11 is not an option, you could try boost::shared_ptr — the standard std::shared_ptr is based on the Boost one. If Boost is not an option either, you could implement your own shared pointer, it's not very hard.

The size of your program is something else to think about. If your application is fairly small and there's little chance for you to forget about some corner case that could cause memory leaks, all of this might be over-engineering. In case simply deleting the objects "by hand" will do then consider doing that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM