Утечка памяти OpenCV C ++ при передаче Mat в поток - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь передать OpenCV Mat из потока захвата изображения в поток обработки изображения как часть большого приложения. У меня нет требования к потоку захвата изображения и потоку обработки изображения для одновременного доступа к мату. В результате я просто хочу передать право собственности на Mat из потока захвата изображения в поток обработки изображения. Я использую OpenCV 3.

Проблема, с которой я сталкиваюсь, заключается в том, что моя программа теряет большой объем памяти.

Ниже я приложил минимальный пример кода, который я использую для передачи циновок между потоками. Когда я запускаю этот код, он заканчивает использовать где-то между 10 МБ и 500 МБ памяти только из 300 изображений с разрешением 1640x1232.

Код

#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 массивом c и индексом.
  • Использование copyTo для перемещения матов из unprocessedImages.
  • Все вышеперечисленное при переносе Mat в shared_ptr или unique_ptr (например, vector<unique_ptr<Mat>> unprocessedImages;).

Ни одна из этих попыток не повлияла на характеристики утечки памяти.

Вопрос

Что вызывает утечку памяти в моей программе? Как вы собираетесь передавать права собственности на OpenCV Mats между разными потоками?

Спасибо, Джеймс

Редактировать: Добавлено дополнительное исправление.

Редактировать 2: Работа с Valgrind приводит к тому, что приведенный выше код НЕ протекает. Это подтверждается отчетом Valgrind, в котором говорится, что все блоки были доступны после завершения программы. Из распечаток программ ясно, что запуск его в valgrind сделал его однопоточным приложением, так как операторы print внутри двух потоков идеально чередуются.

Редактировать 3: я изменил main, как показано ниже. В результате максимальное и минимальное использование памяти на каждой итерации внешнего цикла было одинаковым. На этом конкретном прогоне минимальное использование памяти было 374 МБ.

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...