cvCreateMat 内存泄漏(OpenCV)

Posted

技术标签:

【中文标题】cvCreateMat 内存泄漏(OpenCV)【英文标题】:cvCreateMat memory leak (OpenCV) 【发布时间】:2015-04-14 22:09:40 【问题描述】:

好的;所以当我尝试使用 cvCreateMat 为我即将填充的垫子腾出空间时,我发现了一个奇怪的内存泄漏。以下是我正在尝试做的事情;当我放入 3 通道图像时,adaptiveThreshold 不喜欢它,所以我想将它分成单独的通道。有用!但是每次我们执行这个特定的函数时,我们都会获得另外约 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 增加了 ~3MB inputBlue 增加了 ~1MB inputGreen 增加了 ~1MB inputRed 增加了 ~1MB

到目前为止,一切都很好 - 需要内存来保存数据。 newInputShot 立即获取它的数据,但是 inputRGB 需要从 newInputShot 获取它们的数据 - 所以我们只分配空间以填充即将到来的 for 循环,它(如预期的那样)不分配新内存,只是填充空间已经认领了。

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

释放 inputBlue 释放 0MB 释放 inputGreen 释放 0MB 释放 inputRed 释放 0MB 释放 newInputShot 释放 ~3MB

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

首先,std::vector、Mat 等数据结构使用 函数和方法具有释放底层的析构函数 需要时进行内存缓冲区。这意味着析构函数不会 总是像 Mat 一样释放缓冲区。他们考虑到 帐户可能的数据共享。析构函数递减引用 与矩阵数据缓冲区关联的计数器。缓冲区是 当且仅当引用计数器达到零时才被释放,即 也就是说,当没有其他结构引用同一个缓冲区时。同样,当 一个 Mat 实例被复制,没有实际数据被真正复制。反而, 引用计数器递增以记住还有另一个 相同数据的所有者。还有 Mat::clone 方法 创建矩阵数据的完整副本。

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

这就是我创建 newInputShot 作为克隆的原因(它不会与 inputShot 聚集在一起) - 所以我可以查看 inputRGB 是否发生这种情况。嗯……不! inputRGB 是它们自己的野兽,拒绝被释放。我知道它不是任何中间函数,因为这个 sn-p 做了完全相同的事情:

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 是怎么回事?

【问题讨论】:

如果你使用所有的OpenCV C++ API,你甚至不需要关心这些事情。 绝对避免遗留的c-api。 为什么我被否决了?我完全找不到任何其他说法来不惜一切代价避免遗留 c...是什么让这是一个糟糕的问题? @Alexander 我不知道,这些反对票似乎很随机,也没有任何反对票的解释。我想有些人只是在这里进行一次电力旅行。我会投票的。 【参考方案1】:

我建议不要使用 cvCreateMat 并且您也不需要克隆原始 Mat。 研究使用 split() 和 merge() 函数。他们会为你做这些肮脏的工作,并会返回为你处理内存的 Mat's。我现在没有安装 OpenCV,所以我无法测试任何代码,但我确定这就是你想要采取的路线。

【讨论】:

终于搞定了。花了一些时间来弄清楚 split 应该如何做它的事情;谢谢!

以上是关于cvCreateMat 内存泄漏(OpenCV)的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV 4.0 中的 cvCreateMat

在 OpenCV 应用程序中,我如何识别内存泄漏的来源并修复它?

什么相当于OpenCV2中的cvCreateMat函数使用python3

OpenCV cv::Mat 使用 std::vector 导致潜在的内存泄漏

OpenCV - cvExtractSURF 导致内存泄漏?

与opencv链接时内存泄漏