1. 程式人生 > >可能出現記憶體洩漏的幾種情況

可能出現記憶體洩漏的幾種情況

定義

   簡單來說,記憶體洩漏就是程式在申請一個記憶體空間後沒有釋放,直到程式執行結束後才釋放。這樣看起來似乎沒什麼大問題,但是如果程式會持續執行很長時間(例如伺服器),並且可能在程每次呼叫某個部分的時候都會申請一個記憶體空間,那麼長久以來的後果是可想而知的:當程式希望再次申請一塊空間時,發現已經沒有free的部分了,最終導致系統崩潰。

情況

   記憶體洩漏可能發生在如下幾種條件下:

   1. 類的構造和解構函式不合理。    顯式 --- 很容易想到的情況,使用new在堆裡建立物件後,沒有delete。     隱式 --- 在建構函式或者其他方法體內動態分配記憶體,但是在解構函式中沒有釋放    說明: 以上幾種情況可以通過自定義構造和解構函式解決。

   2. 巢狀的物件指標未清除

   3. 指向物件的指標陣列和物件陣列的區別     物件陣列 --- 一個數組中儲存多個物件,注意釋放時新增 [] 符號。     指向物件的指標陣列 --- 僅僅釋放陣列是不夠的,陣列中的每個元素都指向一個物件,需要一次釋放元素所指物件。    說明: 2 和 3 都是定義未明確時容易出現的錯誤。

   4. 同一個記憶體地址被釋放兩次     缺少拷貝建構函式 --- 如果類成員有指標,那麼在C++中的預設拷貝建構函式同時也會複製指標,從而導致有兩個指標指向同一個地址,那麼在釋放拷貝者物件與被拷貝者物件的時候,同一個地址會被釋放兩次,這是不允許的。需要程式設計師自己新增拷貝建構函式,防止這種問題的出現。     缺少賦值運算子過載函式 --- 和前面一種情況類似,只不過賦值運算子過載函式呼叫的時機與拷貝建構函式不同,解決方法也是程式設計師自己新增賦值運算子過載函式。    說明: 如果一個程式語句生成了一個新的物件例項,那麼它就會呼叫拷貝建構函式;如果這條語句是賦值語句(例如 B = A;)而非初始化語句(例如 ClassB B = A;),那麼它還會呼叫賦值運算子過載函式。注意,這兩者是有可能在同一個語句中呼叫的(例如 B = f1(A);)。

   5. 基類指標指向子類物件時(例如 Parent *p = son;),如果基類的解構函式沒有宣告為虛擬函式,那麼在直接釋放指標 p 時,不會呼叫 Class Son {} 中的解構函式,也就導致派生類物件 son 沒有釋放。