2013-11-01 37 views
1

我使用的是OpenCV,我想將一些圖像(Mat對象)存儲在一個向量中。我已經聲明矢量如下來存儲指向Mat對象的指針。在STL容器中存儲OpenCV 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是reporing一個可能的內存泄漏參照創建墊的對象。我錯過了什麼嗎?

編輯:

確定。顯然最好避免使用Mat指針並使用new動態分配Mat。我修改了我的代碼,以代替std::vector<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); 
} 
+0

墊子類管理內存的分配和有引用計數,這樣'的std ::矢量'做的工作適合你,仍然只複製避免不必要的分配和大型矩陣內容的副本的指針加上大小信息。 – mars

+0

@mars我按照你的建議更新了它的代碼部分後更新了問題。我仍然遇到內存泄漏,但問題仍然存在。 – informer2000

+0

這裏顯示的代碼部分應該可以工作。你能詳細介紹一下這個不透明的指針嗎?它來自哪裏,它如何被初始化,以及誰擁有它,並在不再需要時調用'ImageProcessor'的析構函數?請注意'void * opaque = new ImageProcessor; do_stuff(不透明);自由不透明;'調用'ImageProcessor'的構造函數,但調用'void'的析構函數)。 – mars

回答

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

如果你小心實際刪除對象,那麼就沒有內存泄漏。也就是說,有些方法可以將指針存儲在不容易出現人爲錯誤的向量中(即,您在應用程序的某些特定情況下忘記刪除對象)。

如果你可以使用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不是一個選項,你可以實現你自己的共享指針,這不是很難。

你的程序的大小是別人想的。如果您的應用程序相當小,並且您幾乎沒有機會忘記可能導致內存泄漏的一些特殊情況,所有這些都可能是過度工程。如果簡單地刪除對象「手動」,然後將考慮這樣做。

+0

不幸的是,移植到C++ 11可能並不簡單。有沒有辦法做到這一點,而不使用C + + 11?我的意思是,釋放由使用'new'關鍵字創建的'Mat'對象分配的內存的正確方法是什麼?我知道,創建一個沒有'new'的對象應該在沒有任何引用時釋放所有的資源。但我不確定使用'new'動態創建它。 – informer2000

+0

如果使用'new'創建對象,則必須使用'delete'將其銷燬(在某些時候)。看看我的編輯關於什麼可以考慮作爲C++ 11的替代品。 –

+0

我已更改代碼以避免使用指針並手動分配和刪除對象。我編輯了這個問題以提供更多的細節。但顯然,我仍然面臨同樣的問題。 – informer2000