opencv / opencv

Open Source Computer Vision Library
https://opencv.org
Apache License 2.0
79.38k stars 55.86k forks source link

Memory leak with std::async #23252

Open s-pelliccioli opened 1 year ago

s-pelliccioli commented 1 year ago

System Information

OpenCV version: 4.5.4 and 4.7.0 Operating System / Platform: Ubuntu 22.04 (Jammy Jellyfish) Compiler & compiler version: GCC 11.2.0

Detailed description

Hello, I've recently noticed a memory leak in our production software, inside our image processing pipeline, after switching to a parallel architecture based on std::async. Profiling through Heaptrack, I can see that the leak comes from various functions in OpenCV, like cv::cvtColor and cv::forEach, all of which call cv::parallel_for_ and cv::TLSDataContainer::getData(). It seems that every async thread doesn't release its memory until the entire process is terminated.

cv_mre_flame_graph

I have seen a few closed issues similar to this, but I don't understand if it's something that is supposed to have already been fixed, or if there is a more technical reason why async threads can't release memory at the end of their execution.

If that's the case, is there a patch/workaround to fix this, or is the only solution to abandon std::async and switch to a thread pool implementation ?

Thanks in advance.

Steps to reproduce

#include <opencv2/opencv.hpp>
#include <future>

int main (int argc, char** argv)
{
    cv::Mat random = cv::Mat::zeros(cv::Size(100, 100), CV_8UC3);
    for (int i = 0; i < 1'000; i++)
    {
        cv::randu(random, 0, 255);
        std::async(std::launch::async, [&]()
            {
                cv::Mat result = cv::Mat::zeros(cv::Size(100, 100), CV_8UC1);
                cv::cvtColor(random, result, cv::COLOR_BGR2GRAY);
            }
        ).wait();
    }

    return 0;
}

Expected result: memory usage remains (near-)constant Actual result: memory allocation grow with every async thread. Results below obtained by running the above script, launching 1K and 1M async threads, respectively with a leak of 800KB and 800MB

1) 1'000 threads

cv_mre_memory_nasync_1K cv_mre_leak_report_nasync_1K

2) 1'000'000 threads

cv_mre_memory_nasync_1M cv_mre_leak_report_nasync_1M

Issue submission checklist

s-pelliccioli commented 1 year ago

Minor update: I tried a serial version of the above example, namely a for loop that calls cvtColor() repeatedly on random images. It seems that, independently of how many times it's called, memory is released correctly at every cycle. The leak from cv::TLSDataContainer::getData() is still reported, but keeps constant around 1-1.2 kB.

alalek commented 1 year ago

see here: #9745