C/C++程序内存分配与堆栈详解

程序内存分配五大区域

高地址

栈区(stack)

由编译器自动分配释放,存放函数的参数值、局部变量等

堆区(heap)

由程序员分配释放,若程序员不释放,程序结束时可能由OS回收

全局区/静态区(static)

存放全局变量和静态变量,程序结束后由系统释放

文字常量区

存放常量字符串,程序结束后由系统释放

低地址

程序代码区

存放函数体的二进制代码

栈(stack)的特点

  • 由系统自动分配和释放
  • 存放函数参数和局部变量
  • 操作方式类似数据结构中的栈(LIFO)
  • Windows下默认大小2M(编译时确定)
  • 向低地址扩展,连续内存区域
  • 分配速度快,程序员无法控制

堆(heap)的特点

  • 由程序员分配和释放
  • 使用malloc/new申请,free/delete释放
  • 分配方式类似于链表
  • 向高地址扩展,不连续内存区域
  • 大小受限于计算机有效虚拟内存
  • 分配速度较慢,容易产生内存碎片

代码示例分析

// main.cpp
int a = 0;              // 全局初始化区
char *p1;               // 全局未初始化区
main() {
    int b;              // 栈
    char s[] = "abc";   // 栈
    char *p2;           // 栈
    char *p3 = "123456";// "123456\0"在常量区,p3在栈上
    static int c = 0;   // 全局(静态)初始化区
    p1 = (char *)malloc(10);  // 堆区
    p2 = (char *)malloc(20);  // 堆区
    strcpy(p1, "123456");     // "123456\0"放在常量区
}

函数调用时的堆栈变化

void __stdcall func(int param1, int param2, int param3) {
    int var1 = param1;  // 栈
    int var2 = param2;  // 栈
    int var3 = param3;  // 栈
    // ...
}

int main() {
    func(1, 2, 3);  // 参数从右向左压栈: 3, 2, 1
    return 0;
}
内存地址 内容 说明
0x0012ff78 param1 (1) 第一个参数
0x0012ff7c param2 (2) 第二个参数
0x0012ff80 param3 (3) 第三个参数
0x0012ff68 var1 局部变量1
0x0012ff6c var2 局部变量2
0x0012ff70 var3 局部变量3

堆栈比喻

栈的比喻

就像去饭馆吃饭:

  • 点菜(发出申请)
  • 付钱
  • 吃(使用)
  • 吃饱就走

优点:快捷

缺点:自由度小

堆的比喻

就像自己做饭:

  • 准备食材(申请内存)
  • 烹饪(使用内存)
  • 洗碗刷锅(释放内存)

优点:符合自己口味,自由度大

缺点:比较麻烦

本文来源:关于堆栈的讲解(我见过的最经典的)