将Mat传递到线程时,OpenCV C ++内存泄漏

时间:2018-09-06 04:45:06

标签: c++ multithreading opencv memory-management memory-leaks

我正在尝试将OpenCV Mat从图像捕获线程传递到图像处理线程,这是大型应用程序的一部分。我不需要图像捕获线程和图像处理线程同时访问Mat。结果,我只想将Mat的所有权从图像捕获线程传递到图像处理线程。我正在使用OpenCV 3。

我遇到的问题是我的程序泄漏了大量内存。

下面,我附加了一个用于在线程之间传递Mats的代码的最小示例。当我运行此代码时,它仅使用300张图像(分辨率为1640x1232)完成了10MB到500MB之间的内存使用。

代码

#include <iostream>
#include <thread>
#include <mutex>
#include <opencv2/opencv.hpp>
#include <signal.h>
#include <stdio.h>

#define SIM_PROCESSING_TIME_MS 150

using namespace std;
using namespace cv;

static volatile int keepRunning = 1;
static volatile int runThread = 1;

// Acts as a stack where the last image to be added is the first to be processed.
// If the 'capture' rate is higher than the processing rate then some images are skipped and processed at the end once the 'capture' has stopped.
vector<Mat> unprocessedImages;
mutex unprocessedImageMutex;

void intHandler(int dummy)
{
    keepRunning = 0;
}

// Simulates a function which captures an image using opencv.
Mat GetImage()
{
    return imread("../0000.jpg", CV_LOAD_IMAGE_COLOR);
}

// Simulates an image processing thread.
// A delay has been used to replace any actual image processing as in my testing it didn't seem to make a difference.
void image_processing_thread()
{
    int count = 0;
    while(true)
    {

        Mat imageToProcess;

        {// lock the vector and remove the last element
            lock_guard<mutex> lk(unprocessedImageMutex);
            if (unprocessedImages.size() > 0)
            {
                imageToProcess = unprocessedImages.back();
                unprocessedImages.pop_back();
            }
        }
        if(!imageToProcess.empty())
        {
            // We have an image to process so sleep to simulate processing
            this_thread::sleep_for(std::chrono::milliseconds(SIM_PROCESSING_TIME_MS));
            count++;
            cout << "Processed " << count << endl;
        }
        else if(!runThread) //The image loading thread is done and there are no more images to process
            break;

        this_thread::sleep_for(chrono::milliseconds(1));
    }
}

// Simulates the image capture thread.
// 'Captures' images then pushes them onto unprocessedImages which the image processing thread then reads from.
int main()
{
    signal(SIGINT, intHandler);

    // Start thread to process images
    auto imageProcessingThread = std::thread(image_processing_thread);

    // Load 300 images into memory
    for (int count = 0; count < 300; count++)
    {
        this_thread::sleep_for(std::chrono::milliseconds(20));
        auto img = GetImage();
        lock_guard<mutex> lk(unprocessedImageMutex);
        unprocessedImages.push_back(img);
    }

    // Allow processing thread to exit when it has finished
    runThread = 0;
    cout << "All images loaded in" << endl;
    imageProcessingThread.join();
    cout << "All images processed" << endl;

    while (keepRunning) {}
    return 1;
}

有一些代码,因此可以使用SIGINT退出程序。这段代码不是我较大的应用程序的一部分

尝试修复

  • 在主程序顶部调用unprocessedImages.reserve(1000)
  • unprocessedImages和索引替换std::array
  • 用c数组和索引替换unprocessedImages
  • 使用copyTo将Mats移出unprocessedImages
  • 以上所有内容,同时将Mat包裹在shared_ptrunique_ptr中(例如vector<unique_ptr<Mat>> unprocessedImages;)。

这些尝试都没有影响内存泄漏的特征。

问题

是什么导致程序中的内存泄漏?您如何在不同线程之间传递OpenCV Mat的所有权?

谢谢詹姆斯

编辑:添加了其他尝试的修复程序。

编辑2:与Valgrind一起运行不会导致上述代码泄漏。 Valgrind的报告对此提供了支持,该报告指出程序结束时所有块都可以访问。从程序的打印输出中可以明显看出,在valgrind中运行它使其成为一个单线程应用程序,因为两个线程中的打印语句完美地交织在一起。

编辑3:我如下修改了main。结果是,外循环的每次迭代的峰值和最小内存使用情况都相同。在此特定运行上,最小内存使用为374MB。

int main() {    
    signal(SIGINT, intHandler);

while(keepRunning)
{
runThread = 1;
    // Start thread to process images
    auto imageProcessingThread = std::thread(image_processing_thread);

    /* ... */

    cout << "All images processed" << endl;
}

    while (keepRunning) {}
    return 1;
}

0 个答案:

没有答案