http://blog.csdn.net/feixiaoxing/article/details/6746335node
在 咱們我的編程的過程中,內存泄露雖然不會像內存溢出那樣形成各類莫名奇妙的問題,可是它的危害也是不可忽視的。一方面,內存的泄露致使咱們的軟件在運行 過程當中佔用了愈來愈多的內存,佔有資源而又得不到及時清理,這會致使咱們程序的效率愈來愈低;另外一方面,它會影響咱們用戶的體驗,失去市場的競爭能力。編程
常見的內存泄露是這樣的:緩存
如上圖所示,咱們在函數process的處理過程當中,每一次都須要對內存進行申請,可是在函數結束的時候卻沒有進行釋放。若是這樣的一段代碼出如今業務 側,那麼後果是不可思議的。舉個例子來講,若是咱們服務器每秒鐘須要接受100個用戶的併發訪問,每一個用戶過來的數據,咱們都須要本地申請內存從新保存一 份。處理結束以後,若是內存沒有獲得很好地釋放,就會致使咱們服務器可用的物理內存愈來愈少。一旦達到某一個臨界點以後,操做系統不得不經過內外存的調度 來知足咱們申請新內存的需求,這在另外一方面來說又會下降服務器服務的質量。服務器
內存泄露的危害是不言而喻的,可是查找內存泄露倒是一件苦難並且複雜的工做。咱們都知道,解決bug是一件很是簡單的事情,可是尋找bug的出處倒是一 件很是吃力的事情。所以,咱們有必要在本身編寫代碼的時候,就把查找內存泄露的工做放在很重要的位置上面。那麼有沒有什麼辦法來解決這一問題呢?數據結構
我想要作到解決內存泄露,必須作到下面兩個方面:併發
(1)必須記錄內存在哪一個函數申請的,具體文件的行數是多少函數
(2)內存應該何時被釋放測試
要完成第1個條件其實並不困難。咱們能夠用節點的方法記錄咱們申請的內存:spa
a)設置節點的數據結構操作系統
其中 functionName記錄函數名稱,line記錄行數, pAddress記錄分配的地址, next記錄下一個內存節點。
b)修改內存的分配函數
對業務側的malloc進行函數修改,添加下面一句宏語句
#define malloc(param) MemoryMalloc(__FUNCTION__, __LINE__, param)
在樁函數側書寫下面的代碼
內存的分配過程當中還涉及到了節點的添加,因此咱們還須要添加下面的代碼
文中gMemNode表示全部內存節點的根節點,咱們每增長一次malloc過程就會對內存節點進行記錄。在記錄過程當中,咱們還會記錄調用malloc的函數名稱和具體文件行數,這主要是爲了方便咱們在後面進行故障定位的時候更好地查找。
完成了第一個條件以後,咱們就要對第二個條件進行完成。
a)內存何時釋放,這取決於咱們在函數中是怎麼實現的,可是咱們在編寫測試用例的時候倒是應該知道內存釋放沒有,好比說若是測試用例所有結束了,咱們有理由相信assert(gMemNode == NULL)這應該是恆等於真的。
b)內存釋放的時候,咱們應該作些什麼?和節點的添加同樣,咱們在內存釋放的時候須要free指定的內存,free節點,free節點的內存,下面就是在釋放的時候咱們須要進行的操做
對業務側的free函數進行修改,添加下面一句宏代碼,
#define free(param) MemoryFree(param)
在樁函數側輸入下面的代碼:
在刪除內存的時候,須要刪除節點,刪除節點的內存
有了上面一小段代碼的幫助,咱們在編寫測試用例的時候,就能夠在函數執行後,經過判斷內存節點是否爲空的方法判斷內存是否已經釋放。若是內存沒有釋放,咱們還能經過節點的信息幫助咱們是哪裏發生了錯誤,可是這個方法還有兩個缺點:
(1)沒有考慮緩存的狀況,好多內存分配了以後並不會在函數中立刻釋放,而是放在緩存池中等待下一次調用,這就須要咱們準確把握和判斷了。
(2)代碼中節點刪除和添加的時候沒有考慮多進程的情形,應該考慮用一個互斥鎖或者是信號量加以保護。