跳至主要內容

C语言的内存分布

ekskei大约 4 分钟C/C++内存

C 程序的内存分布

C 程序的典型内存由文本段、数据段、堆和栈4部分组成:

1. 文本段(Text Segment、代码段、代码区)

文本段,也称为代码段或简称为文本,是目标文件或内存中程序的一部分,其中包含可执行指令。文本段放在堆或栈的下面,以防止堆和栈溢出覆盖它。

文本段通常是可共享的,因此对于频繁执行的程序,内存中只需要一个副本。此外,文本段通常是只读的,以防止程序意外修改其指令。

2. 数据段(Data Segment、全局/静态数据段、全局/静态存储区)

分为两部分:

2.1 已初始化数据段(Initialized Data Segment)

初始化数据段,通常简称为Data Segment。数据段是程序虚拟地址空间的一部分,其中包含由程序员初始化的全局变量和静态变量。数据段不是只读的,因为变量的值可以在运行时更改。

该段又可以分为初始化只读区和初始化读写区。
比如C语言中char s[] = "hello world"定义的全局字符串和main外(即global)的int debug=1这样的C语句,都会存放在初始化的读写区中。而像const char* string = "hello world"这样的全局C语句使得字符串文字"hello world"存储在初始化的只读区,字符指针变量string存储在初始化的读写区。

2.2 未初始化的数据段(Uninitialized Data Segment、BSS)

未初始化的数据段通常称为BSS段,代表“由符号开始的块(block started by symbol)”。在程序开始执行之前,该段中的数据由内核初始化为 0 。未初始化的数据从数据段的末尾开始,包含所有初始化为零或在源代码中没有显式初始化的全局变量和静态变量。例如:声明为 static int i 的变量将包含在 BSS 段中;声明为 int j 的全局变量将包含在 BSS 段中。

3. 堆(Heap)

堆是一个可以动态使用的大内存,这一部分内存不是自动管理的,你必须显式地申请(使用如malloc之类的函数)和释放内存(如free)。在变量使用结束时释放内存失败会造成内存泄漏,内存仍然被占用,不能被其它进程获取。与栈区不同,堆区除了物理内存的大小通常没有大小的限制(或者创建变量数量的限制)。在堆区创建的变量可以在程序的任何地方访问。而且堆区内存访问需要用到指针。

4. 栈(Stack)

栈存放局部变量的值、函数调用所需要维护的信息等,由编译器自动分配释放。它是一个LIFO(Last In First Out,后进先出)的结构。每当一个函数声明一个新的变量它将被压入栈中。当一个函数运行结束后,这个函数所有在栈中相关的变量都将被删除,而且它们所占用的内存将会被释放。注意栈区的大小通常都由一个限制,根据操作系统的不同有所不同。如果一个程序尝试将过多的信息放入栈中将会发生栈溢出。栈溢出发生在所有栈区的内存都被分配完,如果继续分配将会溢出至内存的其它部分。在不恰当地使用递归时也会发生栈溢出。

关于 C++ 程序的自由存储区(free store)

自由存储区是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。