在C++中,内存分成4个区:

  • 栈(Stack)
  • 堆(Heap)
  • 数据段(Data Segment)
  • 代码段(Code Segment)

栈区主要存储以下几类数据:

  • 函数的局部变量。
  • 函数参数。
  • 函数返回地址。
  • 编译器生成的额外信息(如变量对齐信息)。

栈区的特点:

  • 自动分配和释放:栈区的内存由编译器和运行时系统自动管理。
  • 高效性:栈的内存分配和释放速度非常快,这是由于栈是顺序存储,不涉及复杂的地址映射。
  • 空间有限:栈区的大小在程序启动时已经固定,通常远小于堆区,因此栈区不适合存储大量或生命周期较长的数据

栈的内存管理基于函数调用过程中的上下文切换。 函数调用时:

  1. 创建一个新的栈帧(Stack Frame)。
  2. 栈帧中保存函数的局部变量、函数参数、返回地址,以及必要的寄存器信息。
  3. 栈指针向低地址移动,分配相应的内存空间。

函数返回时:

  1. 释放当前栈帧占用的内存。
  2. 恢复调用者的上下文,包括返回地址和寄存器值。
  3. 栈指针回到调用函数的位置。

堆区的特点:

  • 动态分配:堆区的内存分配由程序员在运行时通过标准库函数或操作符完成,如mallocnew
  • 手动释放:程序员需要显式释放堆内存,例如通过freedelete,否则会导致内存泄漏。
  • 不连续性:堆内存的分配并不连续,是由内存管理器动态找到的空闲区域。
  • 生命周期由程序控制:堆区内存的存储时间可以延续到程序员主动释放为止。
  • 开销较高:由于堆内存分配需要调用内存管理函数,因此其分配速度通常慢于栈区。

数据段

数据段由以下几部分构成:

  • 未初始化数据区(.bss,Block Started by Symbol):存储未显式初始化的全局变量和静态变量,在初始化时bss段会被编译器清零,属于静态内存分配。
int global_uninit;
static int static_uninit;
  • 已初始化数据区(.data):存储显式初始化的全局变量和静态变量。
int global_var = 10;
static int static_var = 5;
  • 只读数据区(Read-Only Segment):存储不可修改的常量数据。
const int const_var = 100;
const char* str = "Hello";

代码段

代码段也称为文本段 (Text Segment), C++程序运行时存储程序指令的内存区域。它包含程序编译后生成的机器指令,是只读的,用于防止程序运行期间的指令被意外修改。代码段的大小在程序启动时已经确定,与程序的逻辑和编译器的优化程度有关。