2020年第二篇技术文章,最近比较忙,事情比较多,搞了一个新的系列技术文章,还没有完整的搞好,抽空写一篇最近别人问我的事情!
概述
如果你是OpenCV框架做开发、特别是用OpenCV C++版本或者Java/Android版本JNI的调用的化,可能很多时候你遇到最棘手的问题就是程序运行会越来越慢,甚至死机了,原因很简单,有时候你有内存泄漏问题。做好下面几件事情会帮助你在开发中经可能的避免OpenCV对象内存泄漏陷阱。
记得调用release
OpenCV中很多数据结构与对象都有一个release方法,记得用完这些对象跟数据容器之后调用release/destory方法。最典型的就是Mat对象的release方法,调用release并不会重根本上保证立刻回收内存,它只是让对象的引用计数减一,只有当对象的引用计数为0的时候,才会回收内存。此外release方法还是一个原子操作,也可以线程中被调用。这些方法对象列表如下:
对照一下,你平时有注意过这些不,没有的话从现在开始还来得及的!
滥用/重用变量导致内存泄漏
注意要避免下面三种错误代码写法
错误一:
Mat m1;
for (int i = 0; i < 100; i++) {
m1 = Mat::zeros(Size(512, 512), CV_8UC3);
}
imshow("input-m1", m1);
m1.release();
错误方式:在循环中创建无数Mat对象,结果只释放了一个,很多人的循环就是这么写的,妥妥的内存泄漏!类似的代码操作应该避免。
错误二:
Mat image = imread("D:/images/test.png");
image = getProcessed();
imshow("input-image", image);
错误方式:以为可以少创建一个变量,结果是无法释放内存了,反复调用导致内存泄漏,类似的代码应该避免。
错误三:
有返回Mat对象,但是提前调用release释放了,结果再次访问data数据块,导致程序直接崩溃!需要特别注意!简单演示如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat my_process();
int main(int argc, char** argv) {
// 错误三:
Mat image = my_process();
imshow("input-image", image);
waitKey(0);
}
Mat my_process() {
Mat m1 = Mat::zeros(Size(512, 512), CV_8UC3);
// TODO: do something here
m1.release();
return m1;
}
总结
使用C++开发,内存跟指针问题是很多开发者头疼的一件事情,OpenCV框架对内存的管理已经很智能化了,基本上代码规范写,记得release就不会有这个方面的问题,但是还是小心为妙,特别是跨语言调用的时候比如Android/Java通过JNI调用OpenCV函数,如果不注意release或者没有正确release,很难找到原因!