C++ 内存分区详解

C++ 程序运行时,内存通常被划分为以下几个主要区域:

1. 栈区(Stack)

特点:

  • 由编译器自动分配和释放

  • 存储局部变量、函数参数、返回地址等

  • 先进后出(FILO)的数据结构

  • 内存空间有限(通常几MB)

  • 分配速度快

示例:

复制代码
void func() {
    int a = 10;          // a在栈上
    double b = 3.14;     // b在栈上
    char c = 'A';        // c在栈上
} // 函数结束,a,b,c自动释放

2. 堆区(Heap)/ 自由存储区(Free Store)

特点:

  • 程序员手动分配和释放(C:malloc/free,C++:new/delete)

  • 内存空间大,只受系统虚拟内存限制

  • 分配速度较慢

  • 需要防止内存泄漏

示例:

复制代码
int* p1 = new int(10);          // 在堆上分配一个int
int* arr = new int[100];        // 在堆上分配数组
double* p2 = new double(3.14);  // 在堆上分配double

delete p1;     // 手动释放
delete[] arr;  // 释放数组

3. 全局/静态存储区

包含:

A. 数据段(Data Segment)
  • .data段:已初始化的全局变量和静态变量

  • .bss段:未初始化或初始化为0的全局变量和静态变量(程序启动时自动清零)

B. 静态存储区
  • 存储static变量(包括全局static和局部static)

特点:

  • 在程序编译时分配

  • 生命周期贯穿整个程序

  • 程序结束时由系统释放

示例:

复制代码
int global_var = 100;           // .data段(已初始化全局变量)
int global_uninit;              // .bss段(未初始化全局变量)
static int static_global = 50;  // .data段(静态全局变量)

void func() {
    static int static_local = 30;  // 静态局部变量,在.data段
    // 只在第一次进入函数时初始化,保持值不变
}

4. 常量存储区

特点:

  • 存储字符串常量、const修饰的全局常量

  • 只读,不可修改

  • 程序结束时由系统释放

示例:

复制代码
const int MAX_SIZE = 100;      // 可能存储在常量区(优化可能放入代码段)
const char* str = "Hello";     // "Hello"在常量区,str指针在栈或数据段

// 尝试修改会报错或导致未定义行为
// str[0] = 'h';  // 错误!常量区不可修改

5. 代码区(Text Segment)

特点:

  • 存储程序的可执行代码(机器指令)

  • 只读,防止程序意外修改自身指令

  • 在内存中通常有固定位置

6. C++11 新增:线程局部存储区

特点:

  • 每个线程有独立的存储空间

  • 使用 thread_local 关键字声明

示例:

复制代码
thread_local int thread_var = 0;  // 每个线程都有自己的副本

内存布局图示

高地址

┌─────────────────┐

│ 栈区 │ ← 向下生长

├─────────────────┤

│ ... │

├─────────────────┤

│ 堆区 │ ← 向上生长

├─────────────────┤

│ .bss段 │ 未初始化全局/静态变量

├─────────────────┤

│ .data段 │ 已初始化全局/静态变量

├─────────────────┤

│ 常量区 │ 字符串常量等

├─────────────────┤

│ 代码区 │ 程序指令

└─────────────────┘

低地址

代码示例展示不同区域

复制代码
#include <iostream>
using namespace std;

// 全局变量 - 数据段
int global_init = 100;        // .data段
int global_uninit;            // .bss段

// 常量 - 常量区
const int MAX = 1000;         // 常量区
const char* STR = "Hello";    // "Hello"在常量区,STR指针在.data段

void testMemory() {
    // 局部变量 - 栈区
    int local = 10;           // 栈区
    static int static_local = 20;  // .data段(静态局部变量)
    
    // 动态分配 - 堆区
    int* heap_var = new int(30);  // 堆区
    
    // 线程局部存储
    thread_local int tls_var = 40;  // 线程局部存储区
    
    cout << "栈变量地址: " << &local << endl;
    cout << "静态局部变量地址: " << &static_local << endl;
    cout << "堆变量地址: " << heap_var << endl;
    cout << "全局变量地址: " << &global_init << endl;
    cout << "常量地址: " << &MAX << endl;
    cout << "字符串常量地址: " << (void*)STR << endl;
    
    delete heap_var;
}

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

各区域比较表

区域 分配/释放 生命周期 大小限制 访问速度 存储内容
栈区 自动 函数作用域 较小(几MB) 最快 局部变量、参数
堆区 手动 直到delete 大(受系统限制) 动态分配对象
数据段 编译时 程序运行期 中等 全局/静态变量
常量区 编译时 程序运行期 中等 常量、字符串字面量
代码区 编译时 程序运行期 中等 只读 程序指令

注意事项

  1. 栈溢出:递归过深或局部变量过大

    复制代码
    void recursive(int depth) {
        int arr[1000];  // 大量栈分配
        recursive(depth + 1);  // 可能栈溢出
    }
  2. 内存泄漏:堆内存未释放

    复制代码
    void leak() {
        int* p = new int[100];  // 分配
        // 忘记 delete[] p;
    }
  3. 悬空指针:访问已释放内存

    复制代码
    int* p = new int(10);
    delete p;
    *p = 20;  // 错误!p是悬空指针
  4. 多线程安全

    • 栈变量:每个线程独立,安全

    • 全局/静态变量:需要同步机制

    • 堆变量:需谨慎管理所有权

相关推荐
周小码2 小时前
Spacedrive:用Rust构建的虚拟分布式文件系统
开发语言·后端·rust
小张成长计划..2 小时前
【C++】20:set和map的理解和使用
c++
聪明努力的积极向上2 小时前
【设计】分批查询数据通用方法(基于接口 + 泛型 + 定点复制)
开发语言·设计模式·c#
灰色人生qwer2 小时前
VS Code 配置Java环境
java·开发语言
yyy(十一月限定版)2 小时前
C语言——排序算法
c语言·开发语言·排序算法
tgethe2 小时前
Java 链表(LinkedList)
java·开发语言·链表
小鸡吃米…2 小时前
Python - 多重继承
开发语言·python
曼巴UE53 小时前
UE C++ 字符串编码转码
c++·ue5
catchadmin3 小时前
使用 PHP 和 WebSocket 构建实时聊天应用 完整指南
开发语言·websocket·php