赞
踩
在解释bss段与data段区别前,先来看下他们定义,以及内存中的位置。
在32位x86的Linux系统中,虚拟地址空间布局如下图所示:
虚拟地址空间分布
上面只是简单介绍了各个内存段,如果想详细了解,可以看这篇文章《深度解析内存中的程序》。
在初始化时 bss 段部分将会清零。bss 段属于静态内存分配,即程序一开始就将其清零了。
比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。
上面这些理论可能有些抽象,下面我们通过示例代码来对比两者区别。
- #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;// 未初始化的静态局部变量,bss段
- static int bss_4 = 0;// 初始化为0静态局部变量,bss段
- static int data_2 = 1;// 初始化非0静态局部变量,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
反汇编查看变量的存储位置。
- 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

可以看到,变量所处位置与代码中注释的一致。
我们再运行起来, 看一下地址,确实是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
程序1:
- int array[30000];
- int main() {
- return 0;
- }
程序2:
- int array[30000] = {1, 2, 3, 4, 5, 6};
- int main() {
- return 0;
- }
发现【程序2】编译之后所得的文件比【程序1】的要大得多。
【程序1】编译后文件大小
【程序2】编译后文件大小
于是使用 objdump -t
反汇编查看变量 array
所处存储位置。
程序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
命令,查看每个段大小:
- 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
命令,查看每个段大小,因为text,bss,data段在编译时已经决定了进程将占用多少VM:
- size main
- text data bss dec hex filename
- 1099 120560 8 121667 1db43 main
此外,再使用 objdump -s
查看【程序2】中.data段中的数据,可以看到很多很多行的数据:
- 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 ................
- ...省略很多很多行...

未初始化的全局变量、静态局部变量,存储在.bss段中,具体体现为一个占位符;
已初始化的全局变量、静态局部变量,存储在.data段中;
此外,非静态局部变量,都在栈中分配空间。
.bss 是不占用.exe文件空间的,其内容由操作系统初始化(清零);
.data 却需要占用,其内容由程序初始化。因此造成了上述情况。
bss 段,不为数据分配空间,只是记录数据所需空间的大小;
bss 段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在data段后面。
data 段,则为数据分配空间,数据保存在目标文件中;
data 段包含经过初始化的全局变量以及它们的值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。