OpenCV開發中的內存管理問題
- 2020 年 2 月 12 日
- 筆記
2020年第二篇技術文章,最近比較忙,事情比較多,搞了一個新的系列技術文章,還沒有完整的搞好,抽空寫一篇最近別人問我的事情!
概述
如果你是OpenCV框架做開發、特別是用OpenCV C++版本或者Java/Android版本JNI的調用的化,可能很多時候你遇到最棘手的問題就是程序運行會越來越慢,甚至死機了,原因很簡單,有時候你有內存泄漏問題。做好下面幾件事情會幫助你在開發中經可能的避免OpenCV對象內存泄漏陷阱。
記得調用release
OpenCV中很多數據結構與對象都有一個release方法,記得用完這些對象跟數據容器之後調用release/destory方法。最典型的就是Mat對象的release方法,調用release並不會重根本上保證立刻回收內存,它只是讓對象的引用計數減一,只有當對象的引用計數為0的時候,才會回收內存。此外release方法還是一個原子操作,也可以線程中被調用。這些方法對象列表如下:
- Mat的release方法,表示釋放圖像內存
- FileStorage的releaseAndGetString方法,表示關閉文件,釋放所有內存
- Mat繼承類/封裝類,UMat、SparseMat等都調用release方法
- VideoCapture/VideoWriter方法,調用release釋放緩衝區與資源
- CUDA相關的調用releaseMemory方法,比如SURF_CUDA
- rgbd相關的調用releasePyramids方法
- 使用allocate分配內存的必須調用free()方法
對照一下,你平時有注意過這些不,沒有的話從現在開始還來得及的!
濫用/重用變量導致內存泄漏
注意要避免下面三種錯誤代碼寫法
錯誤一:
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,很難找到原因!