1. 程式人生 > 其它 >C/C++記憶體分配管理

C/C++記憶體分配管理

一.編譯的程式佔用記憶體區:

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

堆(heap):堆是作業系統所維護的一塊特殊記憶體,用於程式的記憶體動態分配

生命週期:開發者手動申請和釋放,C使用malloc/free從堆上分配、釋放記憶體,C++使用new/delete;

存放內容malloc、new申請的內容;

棧(stack):在執行函式時由編譯器自動分配與釋放,配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。

生命週期:函式執行結束時自動被釋放

存放內容:執行時函式分配的區域性變數、函式引數、返回資料、返回地址等,如臨時變數、臨時陣列、臨時字串等;

全域性/靜態儲存區:在程式編譯時已分配,全域性區分為已初始化全域性區(data資料區)和未初始化全域性區(bss快取區)

生命週期:整個程式執行期間都存在,程式結束後由系統釋放。

存放內容全域性變數,static修飾的(全域性&區域性)靜態變數。

常量儲存區:生命週期:同全域性變數,程式結束後有系統釋放。存放的是常量(const),不允許修改。如常量字串等;

程式碼區(text):存放函式體(類成員函式和全域性區)的二進位制程式碼

二、3種記憶體分配方式
靜態儲存區分配:

 記憶體在程式編譯的時候已經分配好,這塊記憶體在程式的整個執行期間都存在。例如全域性變數,static變數。

上建立:

 在執行函式時,函式內區域性變數的儲存單元可以在棧上建立,函式執行結束時,這些記憶體單元會自動被釋放。
 棧記憶體分配運算內置於處理器的指令集,效率高,但是分配的記憶體容量有限。

上分配

  亦稱為動態記憶體分配。
 程式在執行的時候使用malloc或者new申請任意多少的記憶體,程式設計師自己負責在何時用free或delete釋放記憶體。
動態記憶體的生命週期有程式設計師決定,使用非常靈活,但如果在堆上分配了空間,既有責任回收它,否則執行的程式會出現記憶體洩漏,頻繁的分配和釋放不同大小的堆空間將會產生記憶體碎片。
三、記憶體分配簡易圖

補充:

在 C 語言中,全域性變數又分為初始化的和未初始化的(未被初始化的物件儲存區可以通過 void* 來訪問和操縱,程式結束後由系統自行釋放),在 C++ 裡面沒有這個區分了,
他們共同佔用同一塊記憶體區。

四、堆和棧的區別
管理方式不同:棧是由編譯器自動申請和釋放空間,堆是需要程式設計師手動申請和釋放;
空間大小不同:棧的空間是有限的,在32位平臺下,VC6下預設為1M,堆最大可以到4G;
能否產生碎片:棧和資料結構中的棧原理相同,在彈出一個元素之前,上一個已經彈出了,不會產生碎片,如果不停地呼叫malloc、free對造成記憶體碎片很多;
生長方向不同:堆生長方向是向上的,也就是向著記憶體地址增加的方向,棧剛好相反,向著記憶體減小的方向生長。
分配方式不同:堆都是動態分配的,沒有靜態分配的堆。棧有靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由 malloc 函式進行分配,但是棧的動態分配和堆是不同的,它的動態分配是由編譯器進行釋放,無需我們手工實現。
分配效率不同:棧的效率比堆高很多。棧是機器系統提供的資料結構,計算機在底層提供棧的支援,分配專門的暫存器來存放棧的地址,壓棧出棧都有相應的指令,因此比較快。堆是由庫函式提供的,機制很複雜,庫函式會按照一定的演算法進行搜尋記憶體,因此比較慢。
五、關於記憶體分配這塊,比較重要的知識點就是動態記憶體管理,

借鑑部落格:
C/C++動態記憶體管理malloc/new、free/delete的異同:
https://blog.csdn.net/cherrydreamsover/article/details/81022039

淺談“C語言動態記憶體管理:malloc/calloc/realloc/free”
https://blog.csdn.net/cherrydreamsover/article/details/81019360

六、靜態全域性變數、全域性變數、靜態區域性變數、區域性變數的區別
靜態全域性變數、全域性變數區別

(1)靜態全域性變數和全域性變數都屬於常量區
(2)靜態全域性區只在本檔案中有效,別的檔案想呼叫該變數,是調不了的,而全域性變數在別的檔案中可以呼叫
(3)如果別的檔案中定義了一個該全域性變數相同的變數名,是會出錯的。

靜態區域性變數、區域性變數的區別

(1)靜態區域性變數是屬於常量區的,而函式內部的區域性變數屬於棧區;
(2)靜態區域性變數在該函式呼叫結束時,不會銷燬,而是隨整個程式結束而結束,但是別的函式調用不了該變數,區域性變數隨該函式的結束而結束;
(3)如果定義這兩個變數的時候沒有初始值時,靜態區域性變數會自動定義為0,而區域性變數就是一個隨機值;
(4)靜態區域性變數在編譯期間只賦值一次,以後每次函式呼叫時,不在賦值,呼叫上次的函式呼叫結束時的值。區域性變數在呼叫期間,每呼叫一次,賦一次值。