C和C++內存模型

如下內容,大部分整理自網絡html

C分爲四個區:堆,棧,靜態全局變量區,常量區linux

C++內存分爲5個區域(堆棧全常代 ):c++

  1. 堆 heap :
    由new分配的內存塊,其釋放編譯器不去管,由咱們程序本身控制(一個new對應一個delete)。若是程序員沒有釋放掉,在程序結束時OS會自動回收。涉及的問題:「緩衝區溢出」、「內存泄露」程序員

  2. 棧 stack :
    是那些編譯器在須要時分配,在不須要時自動清除的存儲區。存放局部變量、函數參數。
    存放在棧中的數據只在當前函數及下一層函數中有效,一旦函數返回了,這些數據也就自動釋放了。數組

  3. 全局/靜態存儲區 (.bss段和.data段) :
    全局和靜態變量被分配到同一塊內存中。在C語言中,未初始化的放在.bss段中,初始化的放在.data段中;在C++裏則不區分了。網絡

  4. 常量存儲區 (.rodata段) :
    存放常量,不容許修改(經過非正當手段也能夠修改)數據結構

  5. 代碼區 (.text段) :
    存放代碼(如函數),不容許修改(相似常量存儲區),但能夠執行(不一樣於常量存儲區)架構

根據c/c++對象生命週期不一樣,c/c++的內存模型有三種不一樣的內存區域,即框架

  1. 自由存儲區,動態區、靜態區。
  2. 自由存儲區:局部非靜態變量的存儲區域,即日常所說的棧
  3. 動態區: 用operator new ,malloc分配的內存,即日常所說的堆
  4. 靜態區:全局變量 靜態變量 字符串常量存在位置

而代碼雖然佔內存,但不屬於c/c++內存模型的一部分函數

在linux系統中,程序在內存中的分佈以下所示:

低地址
.text---> .data --->.bss

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

-->env
高地址

其中 :

  • .text 部分是編譯後程序的主體,也就是程序的機器指令。

  • .data 和 .bss 保存了程序的全局變量,.data保存有初始化的全局變量,.bss保存只有聲明沒有初始化的全局變量。

  • heap(堆)中保存程序中動態分配的內存,好比C的malloc申請的內存,或者C++中new申請的內存。堆向高地址方向增加。

  • stack(棧)用來進行函數調用,保存函數參數,臨時變量,返回地址等。

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程序執行時的內存分配狀況。相關數據在運行時的位置如註釋所述。

//main.cpp
int a = 0;        //a在全局已初始化數據區
char *p1;        //p1在BSS區(未初始化全局變量)
main()
{
int b;        //b在棧區
char s[] = "abc";  //s爲數組變量,存儲在棧區,
//"abc"爲字符串常量,存儲在已初始化數據區
char *p1,*p2;    //p一、p2在棧區
char *p3 = "123456";  //123456\0在已初始化數據區,p3在棧區
static int c =0;    //C爲全局(靜態)數據,存在於已初始化數據區
//另外,靜態數據會自動初始化
p1 = (char *)malloc(10);//分配得來的10個字節的區域在堆區
p2 = (char *)malloc(20);//分配得來的20個字節的區域在堆區
free(p1);
free(p2);
}

來源: http://www.cnblogs.com/zhangsf/p/3835033.html

相關文章
相關標籤/搜索