點選上方藍字關注我們
微信公衆号:OpenCV學堂
關注擷取更多計算機視覺與深度學習知識
引子
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()方法
對照一下,你平時有注意過這些不,沒有的話從現在開始還來得及的!
濫用/重用變量導緻記憶體洩漏
注意要避免下面三種錯誤代碼寫法
錯誤一:
1Mat m1;
2for (int i = 0; i 100; i++) {
3 m1 = Mat::zeros(Size(512, 512), CV_8UC3);
4}
5imshow("input-m1", m1);
6m1.release();
錯誤方式:在循環中建立無數Mat對象,結果隻釋放了一個,很多人的循環就是這麼寫的,妥妥的記憶體洩漏!類似的代碼操作應該避免。
錯誤二:
1Mat image = imread("D:/images/test.png");
2image = getProcessed();
3imshow("input-image", image);
錯誤方式:以為可以少建立一個變量,結果是無法釋放記憶體了,反複調用導緻記憶體洩漏,類似的代碼應該避免。
錯誤三:
有傳回Mat對象,但是提前調用release釋放了,結果再次通路data資料塊,導緻程式直接崩潰!需要特别注意!簡單示範如下:
1#include
2#include
3
4using namespace std;
5using namespace cv;
6Mat my_process();
7int main(int argc, char** argv) {
8 // 錯誤三:
9 Mat image = my_process();
10 imshow("input-image", image);
11 waitKey(0);
12}
13Mat my_process() {
14 Mat m1 = Mat::zeros(Size(512, 512), CV_8UC3);
15 // TODO: do something here
16 m1.release();
17 return m1;
18}
總結
使用C++開發,記憶體跟指針問題是很多開發者頭疼的一件事情,OpenCV架構對記憶體的管理已經很智能化了,基本上代碼規範寫,記得release就不會有這個方面的問題,但是還是小心為妙,特别是跨語言調用的時候比如Android/Java通過JNI調用OpenCV函數,如果不注意release或者沒有正确release,很難找到原因!
最重要的一句話,記得release/free,歡迎留言分享你的觀點與想法!
推薦閱讀
2019原創技術文章彙總
2018年原創技術文章彙總
OpenCV實戰 | 噪聲生成與圖像加噪聲
OpenCV4系統化學習路線圖-視訊版本!