Memory Layout of C Programs

C语言内存模型/内存5区

Posted by Tao on Thursday, March 24, 2022

本文翻译自:Memory Layout of C Programs

C语言程序的典型内存表示由以下部分组成:

  1. Text segment (i.e. instructions)(代码区)
  2. Initialized data segment(全局初始化数据区/静态数据区/代码区ds)
  3. Uninitialized data segment(bss)
  4. Heap
  5. Stack

memoryLayoutC
图1:C语言内存布局

一个正在运行的进程的典型内存布局:

1 Text Segment

文本段,也称为代码段或简称为文本,是object文件或内存中的程序部分之一,其中包含可执行指令。
作为内存区域,文本区应放置于堆区和栈区下方,防止堆栈的覆盖。

通常,文本段是可共享的,因此对于频繁执行的程序(例如文本编辑器、C 编译器、shell 等),只需要在内存中保存一个副本。此外,文本段通常是只读的,以防止程序意外修改其指令。

2 Initialized Data Segment

初始化数据区,通常简称为Data Segment(数据区)。数据区是程序虚拟地址空间的一部分,其包含了由程序员初始化的全局变量和静态变量。
需要注意的是:数据区并不是只读的,因为其中的变量可以在运行时更改。
该区可以进一步分为初始化只读区(initialized read-only area)和初始化读写区(initialized read-write area)。
例如:全局字符串char s[] = "hello world"或一个在 main 外面,类似 int debug=1 这样的语句将被存储在初始化的读写区域中。而像 const char* string = "hello world" 这样的全局 C 语句使字符串文字"hello world"存储在初始化的只读区域中,而字符指针变量 string 则存储在初始化的读写区域中。
再例如:static int i = 10 将存储在数据段中,全局 int i = 10 也将存储在数据段中。

3 Uninitialized Data Segment

未初始化的数据区通常称为“bss”区,以一个古老的汇编运算符命名,代表“block started by symbol”(由符号开始的块)。在程序开始执行前,该区中的数据被内核初始化为数字0。
未初始化的数据从数据段的末尾开始,包含所有初始化为零或没有显式初始化的全局变量和静态变量。
例如:一个声明为 static int i 的变量,将包含在 BSS 段中。声明为 int j 的全局变量也将包含在 BSS 段中。

4 Stack

统上,栈区与堆区相邻,并以相反的方向增长;当栈指针遇到堆指针时,则可用内存耗尽。(利用现代大地址空间和虚拟内存技术,它们几乎可以放置在任何地方,但它们通常仍以相反的方向增长。)
栈区包含程序栈,一个 LIFO(后进先出) 结构,通常位于内存高地址。在标准 x86 计算机体系结构上,它向零地址增长;在其他一些架构上增长方向相反。“栈指针”寄存器跟踪堆栈的顶部;每次将值“推入”堆栈时都会对其进行调整。为一个函数调用推送的一组值称为“堆栈帧”;堆栈帧至少包含一个返回地址。
栈中存储自动变量及每次调用函数时保存的信息。每次调用函数时,返回的地址和调用者环境的某些信息,例如一些机器寄存器,都保存在堆栈中。然后,新调用的函数在栈上为其自动和临时变量分配空间。这就是C语言中递归函数的工作方式。每次递归函数调用自身时,都会使用一个新的堆栈帧,因此一组变量不会干扰来自另一个函数实例的变量。

5 Heap

动态内存分配一般在堆区。
堆区从BSS段末尾开始,并向高地址增长。堆区由mallocreallocfree管理,可以使用brk和sbrk系统调用来调整其大小(note that the use of brk/sbrk and a single “heap area” is not required to fulfill the contract of malloc/realloc/free; they may also be implemented using mmap to reserve potentially non-contiguous regions of virtual memory into the process’ virtual address space)。堆区由进程中的所有共享库和动态加载的模块共享。

6 Examples

size 命令报告文本、数据和 bss 段的大小(以字节为单位)。

  1. Check the following simple C program

    #include <stdio.h>
     
    int main(void)
    {
        return 0;
    }
    
    [narendra@CentOS]$ gcc memory-layout.c -o memory-layout
    [narendra@CentOS]$ size memory-layout
    text       data        bss        dec        hex    filename
    960        248          8       1216        4c0    memory-layout
    
  2. 在程序中添加一个全局变量, 现在来看看bss区的大小。

    #include <stdio.h>
     
    int global; /* Uninitialized variable stored in bss*/
     
    int main(void)
    {
        return 0;
    }
    
    [narendra@CentOS]$ gcc memory-layout.c -o memory-layout
    [narendra@CentOS]$ size memory-layout
    text       data        bss        dec        hex    filename
    960        248         12       1220        4c4    memory-layout
    
  3. 我们再添加一个仍然在bss区的静态变量

    #include <stdio.h>
     
    int global; /* Uninitialized variable stored in bss*/
     
    int main(void)
    {
        static int i; /* Uninitialized static variable stored in bss */
        return 0;
    }
    
    [narendra@CentOS]$ gcc memory-layout.c -o memory-layout
    [narendra@CentOS]$ size memory-layout
    text       data        bss        dec        hex    filename
    960        248         16       1224        4c8    memory-layout
    
  4. 我们来初始化静态变量,这样它会被存入到数据区(DS)

    #include <stdio.h>
     
    int global; /* Uninitialized variable stored in bss*/
     
    int main(void)
    {
        static int i = 100; /* Initialized static variable stored in DS*/
        return 0;
    }
    
    [narendra@CentOS]$ gcc memory-layout.c -o memory-layout
    [narendra@CentOS]$ size memory-layout
    text       data        bss        dec        hex    filename
    960         252         12       1224        4c8    memory-layout
    
  5. 我们来初始化全局变量

    #include <stdio.h>
     
    int global = 10; /* initialized global variable stored in DS*/
     
    int main(void)
    {
        static int i = 100; /* Initialized static variable stored in DS*/
        return 0;
    }
    
    [narendra@CentOS]$ gcc memory-layout.c -o memory-layout
    [narendra@CentOS]$ size memory-layout
    text       data        bss        dec        hex    filename
    960         256          8       1224        4c8    memory-layout
    

Source:
http://en.wikipedia.org/wiki/Data_segment
http://en.wikipedia.org/wiki/Code_segment
http://en.wikipedia.org/wiki/.bss
http://www.amazon.com/Advanced-Programming-UNIX-Environment-2nd/dp/0201433079

「如果这篇文章对你有用,请随意打赏」

Heisenberg Blog

如果这篇文章对你有用,请随意打赏

使用微信扫描二维码完成支付


comments powered by Disqus