本菜雞遇到一個簡單而有趣的bug竟然困擾了挺久。記錄一下,絕不再犯!
背景: 做個Demo,需要統計編碼完每幀圖像的相關信息,比如碼率、質量、編碼參數等信息。
內容:
- 因爲參數分佈在不同的文件和函數裏面,編碼幀數不確定,所以定義了一個全局變量(指針)。
int* InfoRecord = NULL;
- 在根據YUV文件大小、寬高、採樣信息確認了編碼總幀數之後,給指針動態分配內存。
InfoRecord = new int[totalFrames / gopLenth + totalFrames % gopLenth > 0 ? 1 : 0];
- 調用編碼器編碼,調用解碼器解碼,根據 frameIdx 填寫到對應的 InfoRecord 裏面。
- 信息輸出結束,釋放內存。
delete[] InfoRecord;
InfoRecord = NULL;
delete InfoRecord;
問題出現!release沒問題,debug時有時無地進行報錯,修改編碼參數就會影響報錯的頻率!
就這個問題,我一臉懵逼??? new了之後竟然不能delete!!!
-
我一開始認爲 “我定義的全局指針在全局變量區,動態分配的內存在堆區,難道因爲牽扯了全局變量區,這堆區的內存不能讓我來釋放???系統要幫我管理???”
-
於是用VS debug 查看內存,結果是我想得太簡單了,在我令 “InfoRecord = NULL; ”之後,指針分配的內存仍然沒有被釋放,new完不delete果然內存泄漏!!!
- 咋辦呢 ? 我問了旁邊實習的正統計算機本碩的同學,人家說:“臥槽,還有這種事?我也沒見過。"
- 但是,他給我個好解決方法:“你認爲是牽扯了全局變量區所以不能自己釋放!我覺得有道理!那你按照下面這種寫法不就好了”。
① 依舊定義那個全局變量(指針)。
int* InfoRecord = NULL;
② 不要直接對着 InfoRecord 分配內存,先弄個局部變量指針分配內存,再淺拷貝,再釋放這個局部變量指針!
int InfoRecordTmp = new int[totalFrames / gopLenth + totalFrames % gopLenth > 0 ? 1 : 0];
int InfoRecord =InfoRecordTmp;
③ 之後再釋放內存。
delete[] InfoRecordTmp;
InfoRecordTmp = NULL;
delete InfoRecordTmp;
......
delete[] InfoRecord;
InfoRecord = NULL;
delete InfoRecord;
有理啊! 牛掰!
開心解決了這個BUG!!!
結果又是下圖:
???????臨時變量指針都不能delete???????
??????????你是魔鬼嗎 ??????????
??????程序員生涯還沒開始就結束了??????
後來,我在百度、google、csdn上搜索各種“全局變量指針” “new完不能delete”等關鍵詞,都沒有能幫我解決的答案。
還去問了實驗室同學,最後我竟然認爲是超出能力範圍的內存管理問題。
費時費力仔細排查後發現,竟然是=====================》!!!!!!劃重點!!!!!!
本菜雞忽視了運算符順序導致new操作時大小出錯了!
錯誤:
InfoRecord = new int[totalFrames / gopLenth + totalFrames % gopLenth > 0 ? 1 : 0];
三目運算符 ? : 優先級比 + 低,new的大小出錯,導致後面釋放不了!就是少了一個括號的問題!
改成:
InfoRecord = new int[totalFrames / gopLenth + (totalFrames % gopLenth > 0 ? 1 : 0)];
菜雞啊!C++運算符優先級這種最基礎、最基礎的問題都弄錯了,還在那裏亂扯一通堆棧、全局變量區啥的玩意,真是基礎太差!下表罰抄10遍!