日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)

發(fā)布時間:2023/12/18 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

BSS段:(bss segment)通常是指用來存放程序中未初始化全局變量的一塊內(nèi)存區(qū)域。BSS是英文Block Started by Symbol的簡稱。BSS段屬于靜態(tài)內(nèi)存分配。


數(shù)據(jù)段?:數(shù)據(jù)段(data segment)通常是指用來存放程序中?已初始化??全局變量?的一塊內(nèi)存區(qū)域。數(shù)據(jù)段屬于靜態(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。