深入理解BSS段與data段的區(qū)別

在解釋bss段與data段區(qū)別前案淋,先來(lái)看下他們定義妓湘,以及內(nèi)存中的位置员咽。

虛擬地址空間

在32位x86的Linux系統(tǒng)中妆兑,虛擬地址空間布局如下圖所示:

虛擬地址空間分布
  • bss段(bss segment):bss是Block Started by Symbol的簡(jiǎn)稱(chēng),用來(lái)存放程序中未初始化的全局變量的內(nèi)存區(qū)域苏携,屬于靜態(tài)內(nèi)存分配订框。
  • data段(data segment):用來(lái)存放程序中已初始化的全局變量的內(nèi)存區(qū)域,屬于靜態(tài)內(nèi)存分配兜叨。
  • text段(text segment):用來(lái)存放程序執(zhí)行代碼的內(nèi)存區(qū)域。這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定衩侥,并且內(nèi)存區(qū)域通常屬于只讀(某些架構(gòu)也允許代碼段為可寫(xiě)国旷,即允許修改程序)。也有可能包含一些只讀的常數(shù)變量茫死,例如字符串常量等跪但。
  • 堆(heap):用于存放進(jìn)程運(yùn)行中被動(dòng)態(tài)分配的內(nèi)存段,它的大小并不固定峦萎,可動(dòng)態(tài)擴(kuò)張或縮減屡久。
  • 棧(stack):用戶(hù)存放程序臨時(shí)創(chuàng)建的局部變量,也就是說(shuō)我們函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量爱榔,static意味著在data段中存放變量)被环。除此以外,在函數(shù)被調(diào)用時(shí)详幽,其參數(shù)也會(huì)被壓入發(fā)起調(diào)用的進(jìn)程棧中筛欢,并且待到調(diào)用結(jié)束后,函數(shù)的返回值也會(huì)被存放回棧中唇聘。

上面只是簡(jiǎn)單介紹了各個(gè)內(nèi)存段版姑,如果想詳細(xì)了解,可以看這篇文章《深度解析內(nèi)存中的程序》迟郎。

bss段與data段的區(qū)別

在初始化時(shí) bss 段部分將會(huì)清零剥险。bss 段屬于靜態(tài)內(nèi)存分配,即程序一開(kāi)始就將其清零了宪肖。
比如表制,在C語(yǔ)言之類(lèi)的程序編譯完成之后健爬,已初始化的全局變量保存在.data 段中,未初始化的全局變量保存在.bss 段中夫凸。

  • text 和 data 段都在可執(zhí)行文件中浑劳,由系統(tǒng)從可執(zhí)行文件中加載;
  • 而 bss 段不在可執(zhí)行文件中夭拌,由系統(tǒng)初始化魔熏。

上面這些理論可能有些抽象,下面我們通過(guò)示例代碼來(lái)對(duì)比兩者區(qū)別鸽扁。

示例代碼

#include <stdio.h>

int bss_1;// 未初始化的全局變量蒜绽,bss段
int bss_2 = 0;// 初始化為0的全局變量,bss段
int data_1 = 1;// 初始化非0的全局變量桶现,data段
int main() {
    static int bss_3;// 未初始化的靜態(tài)局部變量躲雅,bss段
    static int bss_4 = 0;// 初始化為0靜態(tài)局部變量,bss段
    static int data_2 = 1;// 初始化非0靜態(tài)局部變量骡和,data段
    printf("bss段地址:bss_1 = %p\n", &bss_1);
    printf("bss段地址:bss_2 = %p\n", &bss_2);
    printf("bss段地址:bss_3 = %p\n", &bss_3);
    printf("bss段地址:bss_4 = %p\n\n", &bss_4);

    printf("data段地址:data_1 = %p\n", &data_1);
    printf("data段地址:data_2 = %p\n", &data_2);
    return 0;
}

使用 objdump -t 反匯編查看變量的存儲(chǔ)位置相赁。

gcc bss_data_test.c -o bss_data_test
objdump -t bss_data_test | grep bss_
bss_data_test:     文件格式 elf64-x86-64
0000000000000000 l    df *ABS*  0000000000000000              bss_data_test.c
0000000000601048 l     O .bss   0000000000000004              bss_3.2288
000000000060104c l     O .bss   0000000000000004              bss_4.2289
0000000000601044 g     O .bss   0000000000000004              bss_2
0000000000601040 g       .bss   0000000000000000              __bss_start
0000000000601050 g     O .bss   0000000000000004              bss_1
objdump -t bss_data_test | grep data_
bss_data_test:     文件格式 elf64-x86-64
0000000000000000 l    df *ABS*  0000000000000000              bss_data_test.c
000000000060103c l     O .data  0000000000000004              data_2.2290
0000000000601028  w      .data  0000000000000000              data_start
0000000000601038 g     O .data  0000000000000004              data_1
0000000000601028 g       .data  0000000000000000              __data_start

可以看到,變量所處位置與代碼中注釋的一致慰于。

我們?cè)龠\(yùn)行起來(lái)钮科, 看一下地址,確實(shí)是data段位于bss段的下方

./bss_data_test 
bss段地址:bss_1 = 0x601050
bss段地址:bss_2 = 0x601044
bss段地址:bss_3 = 0x601048
bss段地址:bss_4 = 0x60104c

data段地址:data_1 = 0x601038
data段地址:data_2 = 0x60103c

再來(lái)示例代碼

程序1:

int array[30000];
int main() {
    return 0;
}

程序2:

int array[30000] = {1, 2, 3, 4, 5, 6};
int main() {
    return 0;
}

發(fā)現(xiàn)【程序2】編譯之后所得的文件比【程序1】的要大得多婆赠。

【程序1】編譯后文件大小
【程序2】編譯后文件大小

于是使用 objdump -t 反匯編查看變量 array 所處存儲(chǔ)位置绵脯。

程序1:

objdump -t main | grep array
0000000000600e10 l    d  .init_array    0000000000000000              .init_array
0000000000600e18 l    d  .fini_array    0000000000000000              .fini_array
0000000000600e18 l     O .fini_array    0000000000000000              __do_global_dtors_aux_fini_array_entry
0000000000600e10 l     O .init_array    0000000000000000              __frame_dummy_init_array_entry
0000000000600e18 l       .init_array    0000000000000000              __init_array_end
0000000000600e10 l       .init_array    0000000000000000              __init_array_start
0000000000601060 g     O .bss   000000000001d4c0              array

最后一行可以看到,【程序1】的 array 位于.bss段休里。

我們還可以使用 size 命令蛆挫,查看每個(gè)段大小:

size main
   text    data     bss     dec     hex filename
   1099     544  120032  121675   1db4b main

程序2:

objdump -t main | grep array
0000000000600e10 l    d  .init_array    0000000000000000              .init_array
0000000000600e18 l    d  .fini_array    0000000000000000              .fini_array
0000000000600e18 l     O .fini_array    0000000000000000              __do_global_dtors_aux_fini_array_entry
0000000000600e10 l     O .init_array    0000000000000000              __frame_dummy_init_array_entry
0000000000600e18 l       .init_array    0000000000000000              __init_array_end
0000000000600e10 l       .init_array    0000000000000000              __init_array_start
0000000000601040 g     O .data  000000000001d4c0              array

最后一行可以看到妙黍,【程序2】的 array 位于.data段悴侵。

使用 size 命令,查看每個(gè)段大小拭嫁,因?yàn)閠ext畜挨,bss,data段在編譯時(shí)已經(jīng)決定了進(jìn)程將占用多少VM:

size main
   text    data     bss     dec     hex filename
   1099  120560       8  121667   1db43 main

此外噩凹,再使用 objdump -s 查看【程序2】中.data段中的數(shù)據(jù)巴元,可以看到很多很多行的數(shù)據(jù):

objdump -s main

main:     文件格式 elf64-x86-64
...省略...
Contents of section .data:
 601020 00000000 00000000 00000000 00000000  ................
 601030 00000000 00000000 00000000 00000000  ................
 601040 01000000 02000000 03000000 04000000  ................
 601050 05000000 06000000 00000000 00000000  ................
 601060 00000000 00000000 00000000 00000000  ................
 601070 00000000 00000000 00000000 00000000  ................
 601080 00000000 00000000 00000000 00000000  ................
 601090 00000000 00000000 00000000 00000000  ................
 6010a0 00000000 00000000 00000000 00000000  ................
 6010b0 00000000 00000000 00000000 00000000  ................
 6010c0 00000000 00000000 00000000 00000000  ................
 6010d0 00000000 00000000 00000000 00000000  ................
 6010e0 00000000 00000000 00000000 00000000  ................
 6010f0 00000000 00000000 00000000 00000000  ................
 601100 00000000 00000000 00000000 00000000  ................
 601110 00000000 00000000 00000000 00000000  ................
 601120 00000000 00000000 00000000 00000000  ................
 601130 00000000 00000000 00000000 00000000  ................
 ...省略很多很多行...

總結(jié)

未初始化的全局變量、靜態(tài)局部變量驮宴,存儲(chǔ)在.bss段中逮刨,具體體現(xiàn)為一個(gè)占位符;
已初始化的全局變量、靜態(tài)局部變量修己,存儲(chǔ)在.data段中恢总;
此外,非靜態(tài)局部變量睬愤,都在棧中分配空間片仿。

.bss 是不占用.exe文件空間的,其內(nèi)容由操作系統(tǒng)初始化(清零)尤辱;
.data 卻需要占用砂豌,其內(nèi)容由程序初始化。因此造成了上述情況光督。

bss 段阳距,不為數(shù)據(jù)分配空間,只是記錄數(shù)據(jù)所需空間的大薪峤琛筐摘;
bss 段的大小從可執(zhí)行文件中得到 ,然后鏈接器得到這個(gè)大小的內(nèi)存塊船老,緊跟在data段后面咖熟。

data 段,則為數(shù)據(jù)分配空間柳畔,數(shù)據(jù)保存在目標(biāo)文件中球恤;
data 段包含經(jīng)過(guò)初始化的全局變量以及它們的值。


參考資料:(深入理解計(jì)算機(jī)系統(tǒng)) bss段荸镊,data段、text段堪置、堆(heap)和棧(stack)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末躬存,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子舀锨,更是在濱河造成了極大的恐慌岭洲,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坎匿,死亡現(xiàn)場(chǎng)離奇詭異盾剩,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)替蔬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)告私,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人承桥,你說(shuō)我怎么就攤上這事驻粟。” “怎么了凶异?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蜀撑,是天一觀的道長(zhǎng)挤巡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)酷麦,這世上最難降的妖魔是什么矿卑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮沃饶,結(jié)果婚禮上母廷,老公的妹妹穿的比我還像新娘。我一直安慰自己绍坝,他們只是感情好徘意,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著轩褐,像睡著了一般椎咧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上把介,一...
    開(kāi)封第一講書(shū)人閱讀 49,806評(píng)論 1 290
  • 那天勤讽,我揣著相機(jī)與錄音,去河邊找鬼拗踢。 笑死脚牍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巢墅。 我是一名探鬼主播诸狭,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼君纫!你這毒婦竟也來(lái)了驯遇?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蓄髓,失蹤者是張志新(化名)和其女友劉穎叉庐,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體会喝,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陡叠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肢执。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枉阵。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖预茄,靈堂內(nèi)的尸體忽然破棺而出岭妖,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布昵慌,位于F島的核電站假夺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏斋攀。R本人自食惡果不足惜已卷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淳蔼。 院中可真熱鬧侧蘸,春花似錦、人聲如沸鹉梨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)存皂。三九已至晌坤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旦袋,已是汗流浹背骤菠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疤孕,地道東北人商乎。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像祭阀,于是被迫代替她去往敵國(guó)和親鹉戚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容