C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)
BSS段:(bss segment)通常是指用來存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域。BSS是英文Block Started by Symbol的簡稱。BSS段屬于靜態(tài)內(nèi)存分配。
代碼段:?代碼段(code segment/text segment)通常是指用來存放?程序執(zhí)行代碼?的一塊內(nèi)存區(qū)域。這部分區(qū)域的大小在程序運行前就已經(jīng)確定,并且內(nèi)存區(qū)域通常屬于?只讀?, 某些架構(gòu)也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些?只讀的常數(shù)變量?,例如字符串常量等。程序段為程序代碼在內(nèi)存中的映射.一個程序可以在內(nèi)存中多有個副本.
堆(heap)?:堆是用于存放進(jìn)程運行中被動態(tài)分配的內(nèi)存段,它的大小并不固定,可動態(tài)擴張或縮減。當(dāng)進(jìn)程調(diào)用malloc/free等函數(shù)分配內(nèi)存時,新分配的內(nèi)存就被動態(tài)添加到堆上(堆被擴張)/釋放的內(nèi)存從堆中被剔除(堆被縮減)
棧(stack)?:棧又稱堆棧, 存放程序的?局部變量?(但不包括static聲明的變量,?static?意味著?在數(shù)據(jù)段中?存放變量)。除此以外,在函數(shù)被調(diào)用時,棧用來傳遞參數(shù)和返回值。由于棧的先進(jìn)先出特點,所以棧特別方便用來保存/恢復(fù)調(diào)用現(xiàn)場。儲動態(tài)內(nèi)存分配,需要程序員手工分配,手工釋放
下圖是APUE中的一個典型C內(nèi)存空間分布圖
例如:
#include
int g1=0, g2=0, g3=0;
int max(int i)
{
??? int m1=0,m2,m3=0,*p_max;
??? static n1_max=0,n2_max,n3_max=0;
???? p_max = (int*)malloc(10);
??? printf("打印max程序地址\n");
??? printf("in max: 0x%08x\n\n",max);
??? printf("打印max傳入?yún)?shù)地址\n");
??? printf("in max: 0x%08x\n\n",&i);
??? printf("打印max函數(shù)中靜態(tài)變量地址\n");
??? printf("0x%08x\n",&n1_max); //打印各本地變量的內(nèi)存地址
??? printf("0x%08x\n",&n2_max);
??? printf("0x%08x\n\n",&n3_max);
??? printf("打印max函數(shù)中局部變量地址\n");
??? printf("0x%08x\n",&m1); //打印各本地變量的內(nèi)存地址
??? printf("0x%08x\n",&m2);
??? printf("0x%08x\n\n",&m3);
??? printf("打印max函數(shù)中malloc分配地址\n");
??? printf("0x%08x\n\n",p_max); //打印各本地變量的內(nèi)存地址
if(i) return 1;
??? else return 0;
}
int main(int argc, char **argv)
{
????static int s1=0, s2, s3=0;
????int v1=0, v2, v3=0;
????int *p;????
????p = (int*)malloc(10);
printf("打印各全局變量(已初始化)的內(nèi)存地址\n");
????printf("0x%08x\n",&g1); //打印各全局變量的內(nèi)存地址
????printf("0x%08x\n",&g2);
????printf("0x%08x\n\n",&g3);
????printf("======================\n");
????printf("打印程序初始程序main地址\n");
????printf("main: 0x%08x\n\n", main);
????printf("打印主參地址\n");
????printf("argv: 0x%08x\n\n",argv);
????printf("打印各靜態(tài)變量的內(nèi)存地址\n");
????printf("0x%08x\n",&s1); //打印各靜態(tài)變量的內(nèi)存地址
????printf("0x%08x\n",&s2);
????printf("0x%08x\n\n",&s3);
????printf("打印各局部變量的內(nèi)存地址\n");
????printf("0x%08x\n",&v1); //打印各本地變量的內(nèi)存地址
????printf("0x%08x\n",&v2);
????printf("0x%08x\n\n",&v3);
????printf("打印malloc分配的堆地址\n");
????printf("malloc: 0x%08x\n\n",p);
????printf("======================\n");
??? max(v1);
????printf("======================\n");
????printf("打印子函數(shù)起始地址\n");
????printf("max: 0x%08x\n\n",max);
????return 0;
}
打印結(jié)果:
可以大致查看整個程序在內(nèi)存中的分配情況:
可以看出,傳入的參數(shù),局部變量,都是在棧頂分布,隨著子函數(shù)的增多而向下增長.
函數(shù)的調(diào)用地址(函數(shù)運行代碼),全局變量,靜態(tài)變量都是在分配內(nèi)存的低部存在,而malloc分配的堆則存在于這些內(nèi)存之上,并向上生長.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在操作系統(tǒng)中,一個進(jìn)程就是處于執(zhí)行期的程序(當(dāng)然包括系統(tǒng)資源),實際上正在執(zhí)行的程序代碼的活標(biāo)本。那么進(jìn)程的邏輯地址空間是如何劃分的呢?
引用:
圖1做了簡單的說明(Linux系統(tǒng)下的)
左邊的是UNIX/LINUX系統(tǒng)的執(zhí)行文件,右邊是對應(yīng)進(jìn)程邏輯地址空間的劃分情況。
首先是堆棧區(qū)(stack),堆棧是由編譯器自動分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。棧的申請是由系統(tǒng)自動分配,如在函數(shù)內(nèi)部申請一個局部變量 int h,同時判別所申請空間是否小于棧的剩余空間,如若小于的話,在堆棧中為其開辟空間,為程序提供內(nèi)存,否則將報異常提示棧溢出。 ???
其次是堆(heap),堆一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表。堆的申請是由程序員自己來操作的,在C中使用malloc函數(shù),而C++中使用new運算符,但是堆的申請過程比較復(fù)雜:當(dāng)系統(tǒng)收到程序的申請時,會遍歷記錄空閑內(nèi)存地址的鏈表,以求尋找第一個空間大于所申請空間的堆結(jié)點,然后將該結(jié)點從空閑結(jié)點鏈表中刪除,并將該結(jié)點的空間分配給程序,此處應(yīng)該注意的是有些情況下,新申請的內(nèi)存塊的首地址記錄本次分配的內(nèi)存塊大小,這樣在delete尤其是delete[]時就能正確的釋放內(nèi)存空間。
接著是全局?jǐn)?shù)據(jù)區(qū)(靜態(tài)區(qū)) (static),全局變量和靜態(tài)變量的存儲是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 另外文字常量區(qū),常量字符串就是放在這里,程序結(jié)束后有系統(tǒng)釋放。
最后是程序代碼區(qū),放著函數(shù)體的二進(jìn)制代碼。
舉例說明一下:
int a = 0; ?? ?? ?? ?? ?? ???//全局初始化區(qū)?
char *p1; ?? ?? ?? ?? ?? //全局未初始化區(qū)?
int main()?
{?
????????int b; ?? ?? ?? ?? ?? // 棧?
????????char s[] = "abc"; ?? ?? //棧?
????????char *p2; ?? ?? ?? ?? //棧?
????????char *p3 = "123456"; ???//123456\0在常量區(qū),而p3在棧上。?
????????static int c =0; ?? //全局(靜態(tài))初始化區(qū)?
????????p1 = (char *)malloc(10);
????????p2 = (char *)malloc(20); //分配得來得10和20字節(jié)的區(qū)域就在堆區(qū)。?
????????strcpy(p1, "123456"); ???//123456\0放在常量區(qū),編譯器可能會將它與p3所指向的"123456"優(yōu)化成一個地方。
????????return 0;
}
總結(jié)
以上是生活随笔為你收集整理的C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 社会生活、工作中的著名法则
- 下一篇: 在Windows下编译ffmpeg完全手