收藏 C語言程式記憶體分配中的堆和棧

2021-08-18 13:41:33 字數 3200 閱讀 1519

裡說的是c語言程式記憶體分配中的堆和棧。下面先談談c語言的記憶體管理:

可執行程式在儲存時(沒有調到記憶體)分為**區(text)、資料區(data)和未初始化資料區(bss)3個部分。

(1)**區(text segment)。存放cpu執行的機器指令(machine instructions)。通常,**區是可共享的(即另外的執行程式可以呼叫它),因為對於頻繁被執行的程式,只需要在記憶體中有乙份**即可。**區通常是唯讀的,使其唯讀的原因是防止程式意外地修改它的指令。另外,**區還規劃了區域性變數的相關資訊。

(2)全域性初始化資料區/靜態資料區(initialized data segment/data segment)。該區包含了在程式中明確被初始化的全域性變數、靜態變數(包括全域性靜態變數和區域性靜態變數)和常量資料(如字串常量)。

(3)未初始化資料區(bss區,uninitialized data segment),存入的是全域性未初始化變數。bss區的資料在程式開始執行之前被核心初始化為0或者空指標(null)。

上圖表示可執行**儲存時結構和執行時結構的對照圖。乙個正在執行著的c編譯程式占用的記憶體分為**區、初始化資料區、未初始化資料區、堆區和棧區5個部分。

(1)**區。**區指令根據程式設計流程依次執行,對於順序指令,則只會執行一次(每個程序),如果反覆,則需要使用跳轉指令,如果進行遞迴,則需要借助棧來實現。

**區的指令中包括操作碼和要操作的物件(或物件位址引用)。如果是立即數(即具體的數值),將直接包含在**中;如果是區域性資料,將在棧區分配空間,然後引用該資料位址;如果是bss區和資料區,在**中同樣將引用該資料位址。

(2)全域性初始化資料區/靜態資料區。只初始化一次。

(全域性變數的值可以改變

[cpp]

#include 

using

namespace

std;  

inta = 8;  

intmain()  

輸出     4

)(3)未初始化資料區(bss)。在執行時改變其值。

(4)棧區。由編譯器自動分配釋放,存放函式的引數值、區域性變數的值等。其操作方式類似於資料結構中的棧。每當乙個函式被呼叫,該函式返回位址和一些關於呼叫的資訊,比如某些暫存器的內容,被儲存到棧區。然後這個被呼叫的函式再為它的自動變數和臨時變數在棧區上分配空間,這就是c實現函式遞迴呼叫的方法。每執行一次遞迴函式呼叫,乙個新的棧框架就會被使用,這樣這個新例項棧裡的變數就不會和該函式的另乙個例項棧裡面的變數混淆。

(5)堆區(heap)。用於動態記憶體分配。堆在記憶體中位於bss區和棧區之間。一般由程式設計師分配和釋放,若程式設計師不釋放,程式結束時有可能由os**。

之所以分成這麼多個區域,主要基於以下考慮:

乙個程序在執行過程中,**是根據流程依次執行的,只需要訪問一次,當然跳轉和遞迴有可能使**執行多次,而資料一般都需要訪問多次,因此單獨開闢空間以方便訪問和節約空間。

臨時資料及需要再次使用的**在執行時放入棧區中,生命周期短。

全域性資料和靜態資料有可能在整個程式執行過程中都需要訪問,因此單獨儲存管理。

堆區由使用者自由分配,以便管理。

[cpp]

inta = 0;     

//a在全域性已初始化資料區

char

*p1;     

//p1在bss區(未初始化全域性變數)

void

main()  

記憶體分配方式:

在c語言中,物件可以使用靜態或動態的方式分配記憶體空間。

靜態分配:編譯器在處理程式源**時分配。

動態分配:程式在執行時呼叫malloc庫函式申請分配。

靜態記憶體分配是在程式執行之前進行的,因而效率比較高,而動態記憶體分配則可以靈活處理資料。

靜態與動態記憶體分配的主要區別如下:

靜態物件是有名字的變數,可以直接對其進行操作;動態物件是沒有名字的變數,需要通過指標間接地對它進行操作。

注:這裡我的理解有     如果我們在程式中有寫malloc,它是靜態物件還是動態物件(這是針對「動態物件是沒有名字的變數」)

解答:我的理解有問題,malloc出來的就是在堆中開闢記憶體空間,是沒有名字的。

如:p1 = (char *)malloc(sizeof(int));            //此行**分配了乙個int型別大小的區域在堆區(物件),然後返回物件在記憶體中的位址,接著這個位址被用來初始化指標物件p1,對於動態分配的記憶體唯一的訪問方式是通過指標間接地訪問。

[cpp]

int*p;       

//p中的位址所指向的內容

p;              //p這個變數的內容,這裡p存的是位址,則為位址

&p;           //取p的位址

靜態物件的分配與釋放由編譯器自動處理;動態物件的分配與釋放必須由程式設計師顯式地管理,它通過malloc()和free()兩個函式(c++中為new和delete運算子)來完成。

下面就來正式講講棧與堆的區別:

1、申請方式不同

2、管理方式不同。堆容易產生記憶體洩露。(這個就看程式設計師啦)

3、空間大小不同。

棧是向低位址擴充套件的資料結構,是一塊連續的記憶體區域。這句話的意思是棧頂的位址和棧的最大容量是系統預先規定好的,當申請的空間超過棧的剩餘空間時,將提示溢位。因此,使用者能從棧獲得的空間較小。

堆是向高位址擴充套件的資料結構(它的生長方向與記憶體的生長方向相同),是不連續的記憶體區域。因為系統是用鍊錶來儲存空閒記憶體位址的,且鍊錶的遍歷方向是由低位址向高位址。由此可見,堆獲得的空間較靈活,也較大。

4、系統響應:

棧:只要棧的空間大於所申請空間,系統將為程式提供記憶體,否則將報異常提示棧溢位。

堆:作業系統有乙個記錄空閒記憶體位址的鍊錶,當系統收到程式的申請時,會遍歷該鍊錶,尋找第乙個空間大於所申請空間的堆結點,然後將該結點從空閒鍊錶中刪除,並將該結點的空間分配給程式,另外,對於大多數系統,會在這塊記憶體空間中的首位址處記錄本次分配的大小,這樣,**中的free語句才能正確的釋放本記憶體空間。另外,找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鍊錶中。

對於堆來講,頻繁的malloc/free勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。對於棧就不會存在這個問題。

5、增長方向不同

6、申請效率不同

堆的效率要低於棧。

C 語言動態堆記憶體分配

一 記憶體可以分為棧 堆 靜態儲存區 常量儲存區。二 malloc 分配記憶體 include include includeint main 將malloc分配的記憶體初始化為0 memset p,0,sizeof int void memset void p,int c,int n 對分配的記憶...

記憶體的堆分配和棧分配

記憶體的堆分配和棧分配 備註 這一部分非常重要,如果錯誤請及時告知。謝謝 這裡是完全參考其他部落格。c 記憶體模型 1 棧區 由編譯器自動分配和釋放,存放函式的引數數值,區域性變數的值 其操作方式類似於資料結構中的棧 2 堆區 一般由使用者分配和釋放,若使用者不釋放,程式結束時候由os 它與資料結構...

記憶體的堆分配和棧分配

c 記憶體模型 1 棧區 由編譯器自動分配和釋放,存放函式的引數數值,區域性變數的值 其操作方式類似於資料結構中得棧 2 堆區 一般由使用者分配和釋放,若使用者不釋放,程式結束時候由os 它與資料結構中堆是兩回事,分配方式類似鍊錶 3 全域性區 靜態區 static 全域性變數和靜態變數的存放區域。...