C++ 自由儲存區是否等價於堆?

發表於2017-01-03

“free store” VS “heap”

當我問你C++的記憶體佈局時,你大概會回答:

“在C++中,記憶體區分為5個區,分別是堆、棧、自由儲存區、全域性/靜態儲存區、常量儲存區”。

如果我接著問你自由儲存區與堆有什麼區別,你或許這樣回答:

“malloc在堆上分配的記憶體塊,使用free釋放記憶體,而new所申請的記憶體則是在自由儲存區上,使用delete來釋放。”

這樣聽起來似乎也沒錯,但如果我接著問:

自由儲存區與堆是兩塊不同的記憶體區域嗎?它們有可能相同嗎?

你可能就懵了。

事實上,我在網上看的很多部落格,劃分自由儲存區與堆的分界線就是new/delete與malloc/free。然而,儘管C++標準沒有要求,但很多編譯器的new/delete都是以malloc/free為基礎來實現的。那麼請問:藉以malloc實現的new,所申請的記憶體是在堆上還是在自由儲存區上?

從技術上來說,堆(heap)是C語言和作業系統的術語。堆是作業系統所維護的一塊特殊記憶體,它提供了動態分配的功能,當執行程式呼叫malloc()時就會從中分配,稍後呼叫free可把記憶體交還。而自由儲存是C++中通過new和delete動態分配和釋放物件的抽象概念,通過new來申請的記憶體區域可稱為自由儲存區。基本上,所有的C++編譯器預設使用堆來實現自由儲存,也即是預設的全域性運算子new和delete也許會按照malloc和free的方式來被實現,這時藉由new運算子分配的物件,說它在堆上也對,說它在自由儲存區上也正確。但程式設計師也可以通過過載操作符,改用其他記憶體來實現自由儲存,例如全域性變數做的物件池,這時自由儲存區就區別於堆了。我們所需要記住的就是:

堆是作業系統維護的一塊記憶體,而自由儲存是C++中通過new與delete動態分配和釋放物件的抽象概念。堆與自由儲存區並不等價。

問題的來源

再回過頭來來看看這個問題的起源在哪裡。最先我們使用C語言的時候,並沒有這樣的爭議,很明確地知道malloc/free是在堆上進行記憶體操作。直到我們在Bjarne Stroustrup的書籍中數次看到free store (自由儲存區),說實話,我一直把自由儲存區等價於堆。而在Herb Sutter的《exceptional C++》中,明確指出了free store(自由儲存區) 與 heap(堆) 是有區別的。關於自由儲存區與堆是否等價的問題討論,大概就是從這裡開始的:

Free Store
The free store is one of the two dynamic memory areas, allocated/freed by new/delete. Object lifetime can be less than the time the storage is allocated; that is, free store objects can have memory allocated without being immediately initialized, and can be destroyed without the memory being immediately deallocated. During the period when the storage is allocated but outside the object’s lifetime, the storage may be accessed and manipulated through a void* but none of the proto-object’s nonstatic members or member functions may be accessed, have their addresses taken, or be otherwise manipulated.

Heap
The heap is the other dynamic memory area, allocated/freed by malloc/free and their variants. Note that while the default global new and delete might be implemented in terms of malloc and free by a particular compiler, the heap is not the same as free store and memory allocated in one area cannot be safely deallocated in the other. Memory allocated from the heap can be used for objects of class type by placement-new construction and explicit destruction. If so used, the notes about free store object lifetime apply similarly here.

來源:http://www.gotw.ca/gotw/009.htm

作者也指出,之所以把堆與自由儲存區要分開來,是因為在C++標準草案中關於這兩種區域是否有聯絡的問題一直很謹慎地沒有給予詳細說明,而且特定情況下new和delete是按照malloc和free來實現,或者說是放過來malloc和free是按照new和delete來實現的也沒有定論。這兩種記憶體區域的運作方式不同、訪問方式不同,所以應該被當成不一樣的東西來使用。

結論

  • 自由儲存是C++中通過new與delete動態分配和釋放物件的抽象概念,而堆(heap)是C語言和作業系統的術語,是作業系統維護的一塊動態分配記憶體。
  • new所申請的記憶體區域在C++中稱為自由儲存區。藉由堆實現的自由儲存,可以說new所申請的記憶體區域在堆上。
  • 堆與自由儲存區還是有區別的,它們並非等價。

假如你來自C語言,從沒接觸過C++;或者說你一開始就熟悉C++的自由儲存概念,而從沒聽說過C語言的malloc,可能你就不會陷入“自由儲存區與堆好像一樣,好像又不同”這樣的迷惑之中。這就像Bjarne Stroustrup所說的:

usually because they come from a different language background.

大概只是語言背景不同罷了。

參考資料

C++ 自由儲存區是否等價於堆?
遊戲引擎架構 [Jason Gregory] 電子工業出版社

C++ 自由儲存區是否等價於堆?
exceptional C++ [Herb Sutter]

相關連結:
http://www.gotw.ca/gotw/009.htm
http://zamanbakshifirst.blogspot.tw/2007/02/c-free-store-versus-heap.html

相關文章