- bss 段:存放未初始化的全局变量(包括静态全局变量)和初始化为0的全局变量(包括静态全局变量),属于静态分配内存(bss = Block Started by Symbol)
- data 段:数据段,用来存放已经初始化且初始化值为非零的全局变量(包括静态变量)
- text 段:通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。
- 堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
- 栈(stack):栈又称堆栈,是用户存放程序临时创建的局部变量(不包括静态局部变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。
- 字符常量区(rodata):该区域存放的是字符常量,属于只读区域,有些教材把这个区域归位代码段
全局的未初始化变量存在于 .bss
段中,具体体现为一个占位符;全局的已初始化变量存于 .data
段中;而函数内的自动变量都在栈上分配空间。.bss
是不占用可执行文件空间的,其内容由操作系统初始化(清零);而 .data
却需要占用,其内容由程序初始化,因此同一个全局变量是否赋初值将导致可执行文件的大小发生改变。
.bss
段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小。
.data
(已手动初始化的数据)段则为数据分配空间,数据保存在目标文件中。 数据段包含经过初始化的全局变量以及它们的值。.bss
段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。当这个内存区进入程序的地址空间后全部清零。包含 .data
段和 .bss
段的整个区段此时通常称为数据区。
示例代码:
1int gGlobalInitNonZero = 0x5a5a;
2int gGlobalInitZero = 0;
3int gGlobalUninit;
4
5static int sGlobalInitNonZero = 0x5a5a;
6static int sGlobalInitZero = 0;
7static int sGlobalUninit;
8
9int main()
10{
11 static int localInitNonZero = 12345;
12 static int localInitZero = 0;
13 static int localUninit;
14
15 char *str = "Welcome to the Conference";
16 int stack_start = 0;
17 char *p = str;
18 char *buf = new char('f');
19
20 std::cout << "addr global init non-zero = " << &gGlobalInitNonZero << " (.data)" << std::endl;
21 std::cout << "addr global init zero = " << &gGlobalInitZero << " (.bss)" << std::endl;
22 std::cout << "addr global uninit = " << &gGlobalUninit << " (.bss)" << std::endl;
23
24 std::cout << "addr static global init non-zero = " << &sGlobalInitNonZero << " (.data)" << std::endl;
25 std::cout << "addr static global init zero = " << &sGlobalInitZero << " (.bss)" << std::endl;
26 std::cout << "addr static global uninit = " << &sGlobalUninit << " (.bss)" << std::endl;
27
28 std::cout << "addr static local init non-zero = " << &localInitNonZero << " (.data)" << std::endl;
29 std::cout << "addr static local init zero = " << &localInitZero << " (.bss)" << std::endl;
30 std::cout << "addr static local uninit = " << &localUninit << " (.bss)" << std::endl;
31
32 std::cout << "addr stack_start = " << &stack_start << std::endl;
33 std::cout << "addr on stack = " << &p << std::endl;
34 std::cout << "addr const string = " << static_cast<void *>(str) << std::endl;
35 std::cout << "addr on heap = " << static_cast<void *>(buf) << std::endl;
36 std::cout << "addr text = " << reinterpret_cast<void *>(main) << std::endl;
37}
打印输出:
1addr global init non-zero = 0x7ffe84e02010 (.data)
2addr global init zero = 0x7ffe84e02134 (.bss)
3addr global uninit = 0x7ffe84e02138 (.bss)
4addr static global init non-zero = 0x7ffe84e02014 (.data)
5addr static global init zero = 0x7ffe84e02140 (.bss)
6addr static global uninit = 0x7ffe84e02144 (.bss)
7addr static local init non-zero = 0x7ffe84e02018 (.data)
8addr static local init zero = 0x7ffe84e02148 (.bss)
9addr static local uninit = 0x7ffe84e0214c (.bss)
10addr stack_start = 0x7fffe19ca85c (.stack)
11addr on stack = 0x7fffe19ca860 (.stack)
12addr const string = 0x7ffe84c00fa9 (.rodata)
13addr on heap = 0x7fffd96b6e70 (.heap)
14addr text = 0x7ffe84c00a49 (.text)
Additional sources: