new 和 delete
C++的記憶體申請和釋放是通過 new 和 delete 實現的, 而new 和 delete 其實就是通過 malloc 和 free 實現的。
new 申請記憶體分為三個步驟:
- 呼叫 operator new 函式分配目標型別的記憶體大小,operator new 函式內部就是呼叫的 malloc 函式。
- 將申請得到的記憶體塊強制轉換為目標型別指標。
- 通過指標呼叫目標的建構函式(只有編譯器可以這樣直接呼叫建構函式)。
delete 釋放記憶體分為兩個步驟:
- 呼叫物件的解構函式。
- 呼叫 operator delete 函式釋放物件記憶體,operator delete 函式內部就是呼叫的 free 函式。
array new 和 array delete
array new 是申請多個物件的記憶體。
Cookie
通過 malloc 分配的記憶體,會在記憶體前後加上 cookie,以記錄記憶體分配的總大小,這裡以包含三個 int 資料的 Demo 類為例:
上面 61h 儲存的就是記憶體塊的大小,其中最低位用於表示是否已分配(1表示已分配,0表示已回收),其中的 3 記錄了分配物件的數量。
當申請記憶體後,返回的指標指向資料開始處(00481c34),而使用 delete[] 釋放時,指標會指向00481c30,從而可以根據物件的數量呼叫相應次數的解構函式。如果使用 delete 釋放的話,它不會去00481c30地址獲取物件的長度,而是直接釋放00481c34位置處的物件。
所以,new[] 和 delete[] 需要配合使用,但是如果物件的型別是內建型別或者是無自定義的解構函式的類型別,是可以使用 delete 來釋放 new[] 物件的。否則使用 delete 來釋放物件的話,物件所分配的記憶體空間可以釋放,但是隻會呼叫第一個物件的解構函式,可能導致記憶體洩漏。
對於 cookie,可以從執行速度和空間使用兩個方面去進行改進:
- 減少 malloc 的呼叫次數(雖然 malloc 的速度很快)。
- 每一個 new 的物件都會有上下兩個 cookie,可以預先申請一塊記憶體池,然後供物件例項化,這樣只會在這一整塊的記憶體池上下有 cookie,同時也可以減少 malloc 的呼叫次數。
參考: