cvCreateMat内存泄漏(OpenCV)

cvCreateMat memory leak (OpenCV)

本文关键字:OpenCV 泄漏 内存 cvCreateMat      更新时间:2023-10-16

好的;所以我在尝试使用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增加了约3MB
  • inputBlue增加了约1MB
  • inputGreen增加约1MB
  • inputRed增加了约1MB

到目前为止,一切都很好-需要内存来保存数据。newInputShot立即获取数据,但inputRGB需要从newInputShoot获取数据,因此我们只分配即将到来的for循环中要填充的空间,该循环(如预期)不分配新内存,只填充已经声明的空间。

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

  • 释放inputBlue可释放0MB
  • 释放输入绿色释放0MB
  • 释放inputRed释放0MB
  • 释放新的InputShot可释放约3MB的空间

现在,根据OpenCV文档网站:"OpenCV自动处理所有内存。">

首先函数和方法具有取消分配底层的析构函数需要时使用内存缓冲区。这意味着析构函数不会总是像在Mat的情况下一样取消分配缓冲区帐户可能的数据共享。析构函数递减引用与矩阵数据缓冲器相关联的计数器。缓冲区是解除分配当且仅当引用计数器达到零时是,当没有其他结构引用相同的缓冲区时。类似地,当一个Mat实例被复制,没有实际的数据被真正复制。相反参考计数器递增以记住还有另一个相同数据的所有者。还有Mat::clone方法创建矩阵数据的完整副本。

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

这就是为什么我创建了newInputShot作为克隆(它不会与inputShot聚集在一起),这样我就可以看到这是否与inputRGB一起发生。好不!输入RGB是它们自己的野兽,拒绝被分配。我知道它不是任何中间函数,因为这个片段做了完全相同的事情:

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()和merge()函数。他们会为你做肮脏的工作,并会归还为你处理记忆的垫子。我现在还没有安装OpenCV,所以我不能测试任何代码,但我相信这就是你想要走的路线。