淺析C++中的new operator
因爲這幾天想模擬vector,但是對C++的內存管理機制不太瞭解,所以近段時間一直在關注並搜索着相關信息,我會在我的博客中陸續把成果寫出來,以供大家參考。
經過查閱資料,發現C++在new系統類型和用戶自定義的類型時對內存的分配是不一樣的。我們看下邊的一段代碼:
輸出中的size是16,讀者可能會有疑問,爲什麼不是12?先讓我們想這麼一個問題,new 和 delete 應該是成對使用的,當我們new了一個四個元素的int數組的時候,delete將要做什麼工作?對,是將這16個字節(x86環境下)釋放,但是,當我們new了一個用戶的自定義類型的數組呢?需要釋放多少個字節?不太好說,所以我們需要在新開闢的這段內存中存儲相關的信息,用來保存新開闢內存的大小。
但是當我們把析構函數註釋掉以後,結果又不一樣了,動態申請的僅僅是12個字節,從網上搜索資料,需要多分配字節的有以下三種情況:
1 顯式的聲明瞭析構函數的
2 擁有需要調用析構函數的類的成員的
3 繼承自需要調用析構函數的類的
以下摘自http://apps.hi.baidu.com/share/detail/2188389
下面運行這樣一段代碼做個實驗:
我們直接來看VC2005下Release版本的運行結果,DEBUG版因包含了較多的調試信息,這裏就不分析了:
alloc 0 bytes, address=003A36F0 distance=3815152
alloc 4 bytes, address=003A3700 distance=16
alloc 8 bytes, address=003A3710 distance=16
alloc 12 bytes, address=003A3720 distance=16
alloc 16 bytes, address=003A3738 distance=24
alloc 20 bytes, address=003A84C0 distance=19848
alloc 24 bytes, address=003A84E0 distance=32
alloc 28 bytes, address=003A8500 distance=32
alloc 32 bytes, address=003A8528 distance=40
alloc 36 bytes, address=003A8550 distance=40
每一次分配的字節數都比上一次多4,distance值記錄着與上一次分配的差值,第一個差值沒有實際意義,中間有一個較大的差值,可能是這塊內存已經被分配了,於是也忽略它。結果中最小的差值爲16字節,直到我們申請16字節時,這個差值變成了24,後面也有類似的規律,那麼我們可以認爲申請所得的內存結構是如下這樣的:
從圖中不難看出,當我們要分配一段內存時,所得的內存地址和上一次的尾地址至少要相距8個字節(在DEBUG版中還要更多),那麼我們可以猜想,這8個字節中應該記錄着與這段所分配的內存有關的信息。觀察這8個節內的內容,得到結果如下:
圖中右邊爲每次分配所得的地址之前8個字節的內容的16進製表示,從圖中紅線所表示可以看到,這8個字節中的第一個字節乘以8即得到相臨兩次分配時的距離,經過試驗一次性分配更大的長度可知,第二個字節也是這個意義,並且代表高8位,也就說前面空的這8個字節中的前兩個字節記錄了一次分配內存的長度信息,後面的六個字節可能與空閒內存鏈表的信息有關,在翻譯內存時用來提供必要的信息。這就解答了前面提出的問題,原來C/C++在分配內存時已經記錄了足夠充分的信息用於回收內存,只不過我們平常不關心它罷了。