C++ 程序运行时,操作系统会给进程分配虚拟地址空间,在 32/64 位系统中,逻辑上划分为 代码区、全局静态区、常量区、栈区、堆区 5 个区域。下面从存储内容、管理方式、生命周期、权限、代码示例、常见坑逐一拆解。


一、代码区(Text 段 / 只读代码段)

1. 存储内容

编译后生成的二进制机器指令,包括所有函数的执行代码(main函数、自定义函数、库函数)。

2. 核心特点

  1. 只读:防止程序运行时指令被篡改,避免崩溃;
  2. 可共享:多个运行相同程序的进程,共用同一份代码区,节省内存;
  3. 地址低,程序启动时加载,程序结束才释放

3. 易错点

不能修改代码区内容,比如修改函数指令,会直接触发段错误。


二、全局 / 静态区(Data 段 + BSS 段)

存放全局变量和 **static静态变量 **,整个程序生命周期有效,程序结束由系统回收。分为两个子段:

1. Data 段(已初始化全局区)

  • 存储:初始化的全局变量、初始化的静态局部 / 全局变量

cpp

运行

int g_val = 100; // 全局变量 → Data段
void func() {
    static int s_val = 200; // 静态局部变量 → Data段,**不在栈区**
}

2. BSS 段(未初始化全局区)

  • 存储:未初始化的全局变量、未初始化的静态变量
  • 特点:程序加载时,系统自动将该区域全部置 0,不占用磁盘空间,运行时才分配内存。

cpp

运行

int g_none; // 未初始化全局变量 → BSS段,默认=0
static int s_none; // 静态未初始化 → BSS段

3. 关键易错点

  • static修饰的局部变量,生命周期是全局的,但作用域仅在函数内;
  • 静态变量只会初始化 1 次,函数多次调用不会重复初始化。

三、常量区(只读数据段)

1. 存储内容

  • 字符串字面量("hello");
  • 全局const修饰的常量;
  • 只读的静态常量。

2. 核心特点

  • 只读权限,强行修改直接报 段错误 (Segmentation Fault)
  • 生命周期和程序一致。

3. 代码示例 & 坑点

cpp

运行

// 字符串"abc"存在常量区,str存的是常量区地址
char *str = "abc";
str[0] = 'x'; // ❌ 错误!修改常量区,直接崩溃

const char str2[] = "abc"; // 数组,字符串拷贝到栈上,可修改
str2[0] = 'x'; // ✅ 正确

重点区分:char* str指向常量区;char str[]在栈区。


四、栈区(Stack)

1. 存储内容

  • 局部变量(函数内定义的普通变量);
  • 函数参数、函数返回地址;
  • 函数调用时的临时上下文。

2. 管理方式

系统自动分配、自动释放,无需程序员干预。

  • 函数调用时:栈向下扩展,分配内存;
  • 函数执行结束:栈自动回收,内存释放。

3. 核心特点

  1. 空间:Windows 默认 1M,Linux 默认 8M;
  2. 速度极快:连续内存,CPU 直接寻址;
  3. 结构:先进后出(栈结构)
  4. 内存连续,大小固定,不能动态扩容

4. 常见问题

  1. 栈溢出:递归深度太大、定义超大数组(int arr[10000000]),直接崩溃;
  2. 局部变量出函数后销毁,不能返回局部变量的地址。

cpp

运行

int* test() {
    int a = 10; // a在栈区,函数结束销毁
    return &a; // ❌ 错误:返回栈地址,野指针
}

五、堆区(Heap)

1. 存储内容

程序员动态申请的内存,通过 new / malloc 开辟。

2. 管理方式

完全手动管理

  • 申请:new / malloc
  • 释放:delete / free
  • 忘记释放 → 内存泄漏;释放后继续使用 → 野指针

3. 核心特点

  1. 空间极大,受虚拟内存限制;
  2. 内存不连续,分配速度比栈慢;
  3. 生命周期:由程序员控制,不释放则一直存在,程序结束系统回收。

4. 代码示例

cpp

运行

int* p = new int(10); // 堆区开辟int,值=10
delete p; // 手动释放

int* arr = new int[5]; // 堆数组
delete[] arr;

5. 易错点

  • new[] 必须用 delete[],普通newdelete,不能混用;
  • 释放后指针置空:p = nullptr,避免野指针。

五大内存分区对比总表

表格

分区 管理方式 存储内容 生命周期 读写权限 典型问题
代码区 系统 二进制指令、函数 程序全程 只读 指令篡改崩溃
全局静态区 系统 全局 / 静态变量 程序全程 读写 静态变量全局存活
常量区 系统 字符串常量、全局 const 程序全程 只读 修改直接段错误
栈区 自动分配释放 局部变量、参数 函数内 读写 栈溢出、野指针
堆区 手动 new/delete 动态内存 手动控制 读写 内存泄漏、野指针

补充:完整代码演示(可直接运行观察)

cpp

运行

#include <iostream>
using namespace std;

int g_val = 10;        // 全局区 Data段
int g_none;            // 全局区 BSS段
const char* g_str = "hello"; // 常量区

void test() {
    static int s_val = 20; // 静态局部变量 → 全局区
    int a = 30;            // 栈区
    int* p = new int(40);  // 堆区
    delete p;
}

int main() {
    test();
    return 0;
}

更多推荐