Linux内存管理(.text .data .bss)
Linux內存管理
orisun@orisun-desktop:~/Program$size memory2
text data bss dec hexfilename
2074 284 16 2374 946memory2
可以看到一個可執行程序在存儲(沒有調入內存)時分為代碼區,數據區,未初始化數據區三部分。?
(1)代碼區存放CPU執行的機器指令。通常代碼區是共享的,即其它執行程序可調用它。代碼段(code segment/text segment)通常是只讀的,有些構架也允許自行修改。?
(2)數據區存放已初始化的全局變量,靜態變量(包括全局和局部的),常量。static全局變量和static函數只能在當前文件中被調用。?
(3)未初始化數據區(Block Started by Symbol,BSS)存放全局未初始化的變量。BSS的數據在程序開始執行之前被初始化為0或NULL。?
代碼區所在的地址空間最低,往上依次是數據區和BSS區,并且數據區和BSS區在內存中是緊挨著的。??
text段和data段在編譯時已分配了空間,而bss段并不占用可執行文件的大小,它是由鏈接器來獲取內存的。
bss段(未手動初始化的數據)并不給該段的數據分配空間,只是記錄數據所需空間的大小。特點是:可讀寫的,在程序執行之前BSS段會自動清0。所以,未初始的全局變量在程序執行之前已經成0了。
data(已手動初始化的數據)段則為數據分配空間,數據保存在目標文件中。
?
數據段包含經過初始化的全局變量以及它們的值。BSS段的大小從可執行文件中得到 ,然后鏈接器得到這個大小的內存塊,緊跟在數據段后面。當這個內存區進入程序的地址空間后全部清零。包含數據段和BSS段的整個區段此時通常稱為數據區。
?
?
可執行程序在運行時又多出了兩個區域:棧區和堆區。?
(4)棧區。由編譯器自動釋放,存放函數的參數值,局部變量等。每當一個函數被調用時,該函數的返回類型和一些調用的信息被存儲到棧中。然后這個被調用的函數再為它的自動變量和臨時變量在棧上分配空間。每調用一個函數一個新的棧就會被使用。棧區是從高地址位向低地址位增長的,是一塊連續的內在區域,最大容量是由系統預先定義好的,申請的棧空間超過這個界限時會提示溢出,用戶能從棧中獲取的空間較小。?
(5)堆區。用于動態內存分配,位于BSS和棧中間的地址位。由程序員申請分配(malloc)和釋放(free)。堆是從低地址位向高地址位增長,采用鏈式存儲結構。頻繁地malloc/free造成內存空間的不連續,產生碎片。當申請堆空間時庫函數按照一定的算法搜索可用的足夠大的空間。因此堆的效率比棧要低的多。?
?
舉個例子說明各種變量存放在什么區:?
int a=0; //a在全局已初始化數據區?
char *p1; //p1在BSS區(未初始化全局變量)?
main()
{
int b; //b為局部變量,在棧區?
char s[]="abd"; //s為局部數組變量,在棧區?
//"abc"為字符串常量,存儲在已初始化數據區?
char *p1,*p2; //p1,p2為局部變量,在棧區?
char *p3="123456"; //p3在棧區,123456\0在已初始化數據區?
static int c=0; //c為局部(靜態)數據,在已初始化數據區?
//靜態局部變量會自動初始化(因為BSS區自動用0或NULL初始化)
p1=(char*)malloc(10); //分配得來的10個字節的區域在堆區?
p2=(char*)malloc(20); //分配得來的20個字節的區域在堆區?
free(p1);
free(p2);
p1=NULL; //顯示地將p1置為NULL,避免以后錯誤地使用p1
p2=NULL;
}
?
我們再寫一個程序,輸出各變量的內存空間:?
#include<stdio.h>
#include<malloc.h>
#include<unistd.h>
#include<alloca.h>
?
extern void afunc(void);
extern etext,edata,end;
?
intbss_var;//未初始化全局變量存儲在BSS區
intdata_var=42;//初始化全局就是存儲在數據區
#define SHW_ADR(ID,I) printf("the%8s\t is at address:%8x\n",ID,&I);//打印地址宏
?
int main(int argc,char *argv[])
{
char *p,*b,*nb;
printf("Address etext:%8x\tAddress edata %8x\t Addess end %8x\t\n",&etext,&edata,&end);
SHW_ADR("main",main);//查看代碼段main函數位置
SHW_ADR("afunc",afunc);//查看代碼段afunc函數位置
printf("\nbss Locatoin:\n");
SHW_ADR("bss_var",bss_var);//查看BSS段變量地址
printf("\ndata Location:\n");
SHW_ADR("data_var",data_var);//查看數據段變量
printf("\nStack Loation:\n");
afunc();
p=(char*)alloca(32);//從棧中分配空間
if(p!=NULL)
{
printf("\nthe char p in stackstart from:\t",p);
printf("\nthe char p in stackend in:\t",(p+32*sizeof(char)));
}
b=(char*)malloc(32*sizeof(char));//從堆中分配空間
nb=(char*)malloc(16*sizeof(char));//從堆中分配空間
printf("\nHeapLocations:\n");
printf("the Heap start:%p\n",b);//堆起始地址
printf("the Heap End:%p\n",(nb+16*sizeof(char)));//堆結束位置
printf("\np,b and nb inStack\n");
SHW_ADR("p",p);//顯示棧中數據p的位置
SHW_ADR("b",b);//顯示棧中數據b的位置
SHW_ADR("nb",nb);//顯示棧中數據nb的位置
free(b);//釋放申請的空間,以避免內存泄露
free(nb);
}
?
void afunc(void)
{
static int longlevel=0;//靜態數據存儲在數據段中
int stack_var;//局部變量,存儲在棧區
if(++level==5)
return;
printf("stack_var is at:%p\n",&stack_var);
SHW_ADR("stack_var in stacksection",stack_var);
SHW_ADR("Leval in datasection",level);
afunc();
}
運行結果顯示:
Address etext: 8048818 Addressedata 804a028 Addess end 804a038
the main is at address:80484d4
the afunc is at address:80486e3
?
bss Locatoin:
the bss_var is at address:804a034
?
data Location:
the data_var is at address:804a024
?
Stack Loation:
stack_var is at: 0xbff4a87c
the stack_var in stack section isat address:bff4a87c
the Leval in data section is ataddress: 804a030
stack_var is at: 0xbff4a84c
the stack_var in stack section isat address:bff4a84c
the Leval in data section is ataddress: 804a030
stack_var is at: 0xbff4a81c
the stack_var in stack section isat address:bff4a81c
the Leval in data section is ataddress: 804a030
stack_var is at: 0xbff4a7ec
the stack_var in stack section isat address:bff4a7ec
the Leval in data section is ataddress: 804a030
?
the char p in stack start from:
the char p in stack end in:
Heap Locations:
the Heap start: 0x9b24008
the Heap End: 0x9b24040
?
p,b and nb in Stack
the p is ataddress:bff4a8b8
the b is ataddress:bff4a8b4
the nb is ataddress:bff4a8b0
分析:
由于afunc函數嵌套調用自己,所以很快就把棧空間用完了(sfunc只被調用了四次)。這樣一來p=(char*)alloca(32)想再從棧中申請空間就失敗了。
?
內存管理函數:
void *malloc(size_t size)
void free(void *ptr)
(typedef unsigned int size_t;
這里插入一段對void*的解釋:
void*這不叫空指針,這叫無確切類型指針.這個指針指向一塊內存,卻沒有告訴程序該用何種方式來解釋這片內存.所以這種類型的指針不能直接進行取內容的操作.必須先轉成別的類型的指針才可以把內容解釋出來.
還有'\0',這也不是空指針所指的內容.'\0'是表示一個字符串的結尾而已,并不是NULL的意思.
真正的空指針是說,這個指針沒有指向一塊有意義的內存,比如說:
char* k;
這里這個k就叫空指針.我們并未讓它指向任意地點.
又或者
char* k = NULL;
這里這個k也叫空指針,因為它指向NULL也就是0,注意是整數0,不是'\0'
一個空指針我們也無法對它進行取內容操作.
空指針只有在真正指向了一塊有意義的內存后,我們才能對它取內容.也就是說要這樣
k = "hello world!";
這時k就不是空指針了.)
malloc在內存的動態存儲區中分配一個長度為size字節的連續空間,其參數是無稱號整型,返回一個指向所分配的連續空間的起始地址的指針。分配空間不成功(如內存不足)時返回一個NULL指針。
free釋放掉內存空間。
這兩個函數的庫頭文件為stdlib.h.
void *realloc(void *ptr,size_tsize)
當需要擴大一塊內存空間時realloc試圖直接從堆的當前內存段后面獲得更多的內在空間,并返回原指針;如果空間不夠就使用第一個能夠滿足這個要求的內存塊,并將當前數據復制到新位置,釋放原來的數據塊;如果申請空間失敗,返回NULL。
calloc是malloc的簡單包裝,它把動態分配的內存空間進行初始化,全部清0。此函數的實現描述:
void *calloc(size_t nmemb,size_tsize)
{
void *p;
size_t total;
total=nmemb*size;
p=malloc(total);
if(p!=NULL)//申請空間
memset(p,'\0',total);//初始化\0
return p;
}
alloca()函數在棧中分配size個內存空間(函數返回時自動釋放掉空間,無需程序員手動釋放),并將空間初始化為0。
原文來自:博客園(華夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun總結
以上是生活随笔為你收集整理的Linux内存管理(.text .data .bss)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【欧拉函数】 欧拉函数计算及打表
- 下一篇: JavaWeb中文编码问题方法解析