C C 記憶體模型

2022-03-20 14:40:43 字數 2719 閱讀 6051

c分為四個區:堆,棧,靜態全域性變數區,常量區

c++記憶體分為5個區域(堆疊全常代 ):

堆 heap :

由new分配的記憶體塊,其釋放編譯器不去管,由我們程式自己控制(乙個new對應乙個delete)。如果程式設計師沒有釋放掉,在程式結束時os會自動**。涉及的問題:「緩衝區溢位」、「記憶體洩露」

棧 stack :

是那些編譯器在需要時分配,在不需要時自動清除的儲存區。存放區域性變數、函式引數。

存放在棧中的資料只在當前函式及下一層函式中有效,一旦函式返回了,這些資料也就自動釋放了。

全域性/靜態儲存區 (.bss段和.data段) :

全域性和靜態變數被分配到同一塊記憶體中。在c語言中,未初始化的放在.bss段中,初始化的放在.data段中;在c++裡則不區分了。

常量儲存區 (.rodata段) :

存放常量,不允許修改(通過非正當手段也可以修改)

**區 (.text段) :

存放**(如函式),不允許修改(類似常量儲存區),但可以執行(不同於常量儲存區)

根據c/c++物件生命週期不同,c/c++的記憶體模型有三種不同的記憶體區域,即

自由儲存區,動態區、靜態區。

自由儲存區:區域性非靜態變數的儲存區域,即平常所說的棧

動態區: 用operator new ,malloc分配的記憶體,即平常所說的堆

靜態區:全域性變數 靜態變數 字串常量存在位置

而**雖然佔記憶體,但不屬於c/c++記憶體模型的一部分

在linux系統中,程式在記憶體中的分布如下所示:

低位址

.text---> .data --->.bss

--->heap(堆) --> unused <-- stack(棧)

-->env

高位址

其中 :

bss 是「block started by symbol」的縮寫,意為「以符號開始的塊」。bss是unix鏈結器產生的未初始化資料段。其他的段分別是包含程式**的 「text」段和包含已初始化資料的「data」段。bss段的變數只有名稱和大小卻沒有值。此名後來被許多檔案格式使用,包括pe。「以符號開始的塊」 指的是編譯器處理未初始化資料的地方。bss節不包含任何資料,只是簡單的維護開始和結束的位址,以便記憶體區能在執行時被有效地清零。bss節在應用程式 的二進位制映象檔案中並不存在。

在採用段式記憶體管理的架構中(比如intel的80x86系統),bss段(block started by symbol segment)通常是指用來存放程式中未初始化的全域性變數的一塊記憶體區域,一般在初始化時bss 段部分將會清零。bss段屬於靜態記憶體分配,即程式一開始就將其清零了。

比如,在c語言之類的程式編譯完成之後,已初始化的全域性變數儲存在.data 段中,未初始化的全域性變數儲存在.bss 段中。

text和data段都在可執行檔案中(在嵌入式系統裡一般是固化在映象檔案中),由系 統從可執行檔案中載入;而bss段不在可執行檔案中,由系統初始化。

乙個正在執行著的c編譯程式占用的記憶體分為**區、初始化資料區、未初始化資料區、堆區 和棧區5個部分。

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

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

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

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

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

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

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

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

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

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

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

下面通過一段簡單的**來檢視c程式執行時的記憶體分配情況。相關資料在執行時的位置如注釋所述。

1

2int a = 0; //

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

3char *p1; //

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

4main()

5

c c 程式的記憶體分割槽模型詳解

我們要想執行我們編寫的c程式,那麼第一步需要對這個程式進行編譯。預處理 巨集定義展開 標頭檔案展開 條件編譯,這裡並不會檢查語法 編譯 檢查語法,將預處理後檔案編譯生成彙編檔案 彙編 將彙編檔案生成目標檔案 二進位制檔案 在沒有執行程式前,也就是說程式沒有載入到 記憶體前,可執行程式內部已經分好3段...

C C 筆記 記憶體四區模型

作業系統給c c 編寫的程式分配記憶體,通常將分配的記憶體劃分為以下四個區域 用於存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。用完由作業系統自動釋放,一般是由編譯器自動分配釋放的。棧向下生長,棧分配的位址越來越小。動態分配給程式的記憶體區域,由程式設計師手動釋放,若程式設計師...

型別記憶體模型(物件記憶體模型)

型別的記憶體模型的3個問題 1 包含什麼 附加資訊 2 怎麼布局 記憶體對齊 3 使用場景 怎麼使用附加資訊 除了包含結構型別的顯式成員變數外,型別記憶體模型需要解決附加資訊的引入問題 1 附加資訊 opaque 有哪些 型別資訊 函式資訊 繼承資訊 記憶體計數等 2 為什麼有附加資訊 1 解決多型...