cvCreateMat 内存泄漏(OpenCV)

cvCreateMat memory leak (OpenCV)

好的;所以当我尝试使用 cvCreateMat 为我即将填充的垫子腾出空间时,我发现了一个奇怪的内存泄漏。以下是我正在尝试做的事情; adaptiveThreshold 不喜欢我把 3 通道图像放进去,所以我想把它分成单独的通道。有用!但是每次我们执行这个特定的函数时,我们都会获得另外 ~3MB 的内存。由于此函数预期 运行 几百次,因此这成为一个相当 值得注意的 问题。

代码如下:

void adaptiveColorThreshold(Mat *inputShot, int adaptiveMethod, int blockSize, int cSubtraction)
{
    Mat newInputShot = (*inputShot).clone();
    Mat inputBlue = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
    Mat inputGreen = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
    Mat inputRed = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);

    for(int rows = 0; rows < newInputShot.rows; rows++)
    {
        for(int cols = 0; cols < newInputShot.cols; cols++)
        {
            inputBlue.data[inputBlue.step[0]*rows + inputBlue.step[1]*cols] = newInputShot.data[newInputShot.step[0]*rows + newInputShot.step[1]*cols + 0];
            inputGreen.data[inputGreen.step[0]*rows + inputGreen.step[1]*cols] = newInputShot.data[newInputShot.step[0]*rows + newInputShot.step[1]*cols + 1];
            inputRed.data[inputRed.step[0]*rows + inputRed.step[1]*cols] = newInputShot.data[newInputShot.step[0]*rows + newInputShot.step[1]*cols + 2];
        }
    }

    adaptiveThreshold(inputBlue, inputBlue, 255, adaptiveMethod, THRESH_BINARY, blockSize, cSubtraction);
    adaptiveThreshold(inputGreen, inputGreen, 255, adaptiveMethod, THRESH_BINARY, blockSize, cSubtraction);
    adaptiveThreshold(inputRed, inputRed, 255, adaptiveMethod, THRESH_BINARY, blockSize, cSubtraction);

    for(int rows = 0; rows < (*inputShot).rows; rows++)
    {
        for(int cols = 0; cols < (*inputShot).cols; cols++)
        {
            (*inputShot).data[(*inputShot).step[0]*rows + (*inputShot).step[1]*cols + 0] = inputBlue.data[inputBlue.step[0]*rows + inputBlue.step[1]*cols];
            (*inputShot).data[(*inputShot).step[0]*rows + (*inputShot).step[1]*cols + 1] = inputGreen.data[inputGreen.step[0]*rows + inputGreen.step[1]*cols];
            (*inputShot).data[(*inputShot).step[0]*rows + (*inputShot).step[1]*cols + 2] = inputRed.data[inputRed.step[0]*rows + inputRed.step[1]*cols];
        }
    }

    inputBlue.release();
    inputGreen.release();
    inputRed.release();
    newInputShot.release();

    return;
}

所以一次一行地浏览它...

到目前为止一切顺利 - 需要内存来保存数据。 newInputShot 立即获取它的数据,但是 inputRGB 需要从 newInputShot 获取它们的数据 - 所以我们只分配 space 以在即将到来的 for 循环中填充,这(正如预期的那样)不分配新内存,只是填写已领取的space。

adaptiveThresholds 也不添加任何新内存,因为它们只是应该覆盖已经存在的内容,而下一个 for 循环直接写入 inputShot;那里不需要新的内存。所以现在我们开始(手动)释放内存。

现在,根据 OpenCV 文档站点:“OpenCV handles all the memory automatically.

First of all, std::vector, Mat, and other data structures used by the functions and methods have destructors that deallocate the underlying memory buffers when needed. This means that the destructors do not always deallocate the buffers as in case of Mat. They take into account possible data sharing. A destructor decrements the reference counter associated with the matrix data buffer. The buffer is deallocated if and only if the reference counter reaches zero, that is, when no other structures refer to the same buffer. Similarly, when a Mat instance is copied, no actual data is really copied. Instead, the reference counter is incremented to memorize that there is another owner of the same data. There is also the Mat::clone method that creates a full copy of the matrix data.

TLDR 引用:相关的垫子聚集在一个超级垫子中,当没有任何东西使用它时,它会立即释放。

这就是我创建 newInputShot 作为克隆的原因(它不会与 inputShot 混为一谈)- 这样我就可以看到这是否与 inputRGB 一起发生。好吧……不! inputRGBs 是他们自己的野兽,拒绝被释放。我知道它不是任何中间函数,因为这个片段做了完全相同的事情:

void adaptiveColorThreshold(Mat *inputShot, int adaptiveMethod, int blockSize, int cSubtraction)
{
    Mat newInputShot = (*inputShot).clone();
    Mat inputBlue = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
    Mat inputGreen = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
    Mat inputRed = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);

    inputBlue.release();
    inputGreen.release();
    inputRed.release();
    newInputShot.release();

    return;
}

就这么简单。分配 - 无法取消分配。那么 cvCreateMat 是怎么回事?

我建议不要使用 cvCreateMat 并且您也不需要克隆原始 Mat。 考虑使用 split() and merge() 函数。他们会为您完成肮脏的工作,并会 return Mat's 为您处理内存。我现在没有安装 OpenCV,所以我无法测试任何代码,但我确定这就是您要采用的方法。