前言
最近在開發調試基于RT-Thread 的程序時,遇到一個比較奇怪的死機問題,后來經過一步步排查,終于發現是動態內存申請的數據結構沒有清零引發的死機。
排查方法
由于沒有單步調試的手段,就通過 打印調試LOG 與 #if 0 A_CODE #else B_CODE #endif 條件編譯的方式,通過注釋部分代碼等方法,快速縮小問題的排查范圍。
最終逐步排查,定位在內存資源釋放的函數部分 xxfree,也就是程序執行完了,釋放動態申請的內存時,觸發了死機,注釋掉這部分代碼,不死機了,不過這樣會造成【內存泄露】
通過查看代碼繼續排查,xxfree 函數設計的沒有問題,所有指針都有判空操作,也就是只會 free 非空的指針,但是這種必現的死機,就幾段內存 free 的代碼,排查應該容易,所以增加了些LOG,并且把 free 時的指針地址也打印出來,確認是否 free 了不屬于自己的指針或者重復 free 指針。
問題定位
在 xxfree 函數 增加多行 LOG后,再次運行死機后,我看了一下死機后的 LOG 信息,瞬間找到了方向,原來 free 的指針不是NULL,而是 0xffffffff,怪不得會死機!
通過全局搜索這個指針成員,竟沒有發現賦值的地方,也就是沒有賦值,希望它為 NULL,而它實際上是 0xffffffff。
這個指針附屬于一個大的結構體,這個結構體是通過 malloc 方式動態內存申請的,但是沒有【清零】操作,并且后續的操作中,這個指針成員由于某種條件下,沒有代碼執行到賦值,默認【野指針】。并且這個板子動態申請的內存默認不是0x00,而是 0xff,所以 free 了 非空的野指針觸發死機
解決方法:malloc 后的數據結構,增加 memset 清零操作,這樣保證指針成員默認為 NULL,如果是野指針, 并且free 時不為 NULL,會造成釋放內存操作異常,大概率觸發死機。
觸累與排雷
繼續排查驅動里面,有幾處也是通過動態內存申請 malloc 數據結構 后,也沒有 memset 清零,并且里面有 鏈表成員,鏈表也沒有初始化,并且【僥幸成功】的掛上了 鏈表頭 head 上,沒有觸發死機。
由于 資源釋放這個操作一般都發生在【游戲結束】后,也就是代碼不運行了,所以沒有特別的注意,即使鏈表的成員沒有清零操作,指針為野指針,也能 插入到 鏈表頭,但是當多次這種操作后,就會觸發內存異常,因為沒有【清零】的內存空間,數據可能不是零,在地雷的旁邊走,就有踩上去的機會!
加了 memset 清零操作后,果然觸發了幾個死機,并且牽出來 【鏈表未初始化】 就直接使用的 BUG 操作。
有些操作可能運行一次并未發生死機等【當場就出現】的死機等錯誤,但是多次運行,錯誤累積起來,就會觸發更嚴重的錯誤
代碼編寫時,規范化、充分測試非常有必要。
調試改善代碼的時間往往比編寫代碼時間多很多,因此在代碼設計編寫時要多花點心思與時間,充分驗證,減少后續問題的排查調試時間,提高工作效率。
小結
復雜點的數據結構,使用 動態內存申請后,建議直接 清零操作,以免默認的數據不是自己想要的,造成程序運行異常或者死機,簡單的數據結構,如果能保證后面的操作把每個成員都賦值上,可以不清零。
初始化、清零,這些簡單的操作,也需要重視起來,以免耗費大量的軟件排查與調試時間。
-
動態內存
+關注
關注
1文章
24瀏覽量
7961 -
RT-Thread
+關注
關注
31文章
1273瀏覽量
39924
發布評論請先 登錄
相關推薦
評論