内存布局
在C++中,内存分成4个区:
- 栈(Stack)
- 堆(Heap)
- 数据段(Data Segment)
- 代码段(Code Segment)
栈
栈区主要存储以下几类数据:
- 函数的局部变量。
- 函数参数。
- 函数返回地址。
- 编译器生成的额外信息(如变量对齐信息)。
栈区的特点:
- 自动分配和释放:栈区的内存由编译器和运行时系统自动管理。
- 高效性:栈的内存分配和释放速度非常快,这是由于栈是顺序存储,不涉及复杂的地址映射。
- 空间有限:栈区的大小在程序启动时已经固定,通常远小于堆区,因此栈区不适合存储大量或生命周期较长的数据。
栈的内存管理基于函数调用过程中的上下文切换。 函数调用时:
- 创建一个新的栈帧(Stack Frame)。
- 栈帧中保存函数的局部变量、函数参数、返回地址,以及必要的寄存器信息。
- 栈指针向低地址移动,分配相应的内存空间。
函数返回时:
- 释放当前栈帧占用的内存。
- 恢复调用者的上下文,包括返回地址和寄存器值。
- 栈指针回到调用函数的位置。
堆
堆区的特点:
- 动态分配:堆区的内存分配由程序员在运行时通过标准库函数或操作符完成,如
malloc
和new
。 - 手动释放:程序员需要显式释放堆内存,例如通过
free
或delete
,否则会导致内存泄漏。 - 不连续性:堆内存的分配并不连续,是由内存管理器动态找到的空闲区域。
- 生命周期由程序控制:堆区内存的存储时间可以延续到程序员主动释放为止。
- 开销较高:由于堆内存分配需要调用内存管理函数,因此其分配速度通常慢于栈区。
数据段
数据段由以下几部分构成:
- 未初始化数据区(.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++程序运行时存储程序指令的内存区域。它包含程序编译后生成的机器指令,是只读的,用于防止程序运行期间的指令被意外修改。代码段的大小在程序启动时已经确定,与程序的逻辑和编译器的优化程度有关。