我正在尝试将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
。unprocessedImages
。copyTo
将Mats移出unprocessedImages
。Mat
包裹在shared_ptr
或unique_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;
}