C/C++ 存储区知识

  • 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:


TTY, Terminal & Console on Linux
About