array new 與 array delete

@Me發表於2015-12-13

以前在看C++書和上C++課的時候可以看到

delete[] pointer;

的用法,而大多數對於這個用法沒有具體的解釋,多是看到:

有一個delete運算子的特殊語法,可以釋放動態分配的陣列記憶體:

delete[] p_numbers;

方括號告訴編譯器,指標指向了一個陣列,而不是單個值。

引文自:《C++程式設計:現代方法》,14.2 指標和陣列

也沒有說明如果缺少[]會帶來的後果,猜想是記憶體洩露,但是不明就裡,於是給我來帶了C++記憶體管理詭譎的印象。不過最近侯捷先生的講解卻很是清晰。

下方所說Complex類為僅包含兩個double型別成員,String僅含一個char型別指標。

構造

首先說的是構造,以Complex類為例:

Complex *c = new Complex(1,2);

執行過程為:

Complex *c;
void* mem = operator new( sizeof(Complex) ); //內部呼叫malloc(n),分配記憶體
c = static_cast<Complex*>(mem);              //型別轉換
c->Complex::Complex(1,2);                    //→Complex::Complex(c,1,2),建構函式

那麼在記憶體中執行的時候分配記憶體為:

enter image description here

紅色部分為作業系統分配之Cookie,藍色部分為填充位,目的是為了讓整個長度為16的倍數。灰色區域內資料僅在Debug模式下出現,綠色區域為物件所佔長度。可計算,Debug模式下的Complex例項長度為:

8[兩個雙精度浮點實數] + (32+4)[除錯模式] + (4×2)[Cookie] → 52 + 12[填充] → 40H

那麼此時向作業系統取記憶體時Cookie末位置1,即Cookie為00000041,釋放時末位置0。之所以保持16(10H)的倍數即如此。

Release下的String型別長度則為:

4[指標] + (4×2)[Cookie] → 12 + 4[填充] → 10H

釋放

執行

String *s = new String(1,2);
…
delete s;

delete s的時候會:

String::~String(s);     //解構函式
operator delete(s);     //釋放記憶體,其內部呼叫free(s)

即執行String類解構函式後釋放記憶體,釋放Cookie標記段。看起來似乎沒什麼問題。

陣列

看一下

Complex *c = new Complex [3];

String *s = new String [3];

的記憶體結構,可以發現是這樣的:

enter image description here

在頂部多儲存了一個陣列長度。那麼執行deletedelete[]有什麼區別呢?是這樣的:

enter image description here

可以看到,對於記憶體而言,delete一定會將Cookie標記段給釋放掉,如果是類似Complex的陣列,那麼使用deletedelete[]的效果是一致的,但是針對String這類含指標型別的陣列,使用delete僅執行首次析構,也就是在這裡出現了記憶體洩漏。


最近怎麼關心記憶體洩漏了?

程式跑了一晚上洩漏了8G記憶體,不關心一下怎麼得了。

相關文章