C++ 系统学习日记・第 11 天|程序内存模型 —— 内存四区全解

3 阅读5分钟

📖 学习信息

学习课程:黑马 C++ 零基础入门教程

本日学习:C++ 程序内存四区原理包含:内存四区整体划分、代码区、全局区、栈区、堆区、各区特点与生命周期、栈与堆区别、new/delete 动态内存分配、常见内存错误


一、前言

程序运行起来后,会在内存中划分出四块固定区域,分别是:代码区、全局区、栈区、堆区

所有变量、函数、常量、对象、动态内存,本质都分配在这四个区域里。搞懂内存四区,就能彻底理解:变量生命周期、指针原理、引用、函数传参、new/delete、野指针、内存泄漏 等底层逻辑。


二、内存四区整体介绍

程序运行时内存分为 4 大区域:

  1. 代码区:存放函数二进制代码、程序指令
  2. 全局区:存放全局变量、静态变量、常量
  3. 栈区:由系统自动分配释放,存放局部变量、函数形参
  4. 堆区:由程序员手动分配释放,手动开辟动态内存

四区核心口诀

代码只读、全局全程、栈自动释放、堆手动管理


三、各区详细讲解

1. 代码区

存放内容

  • 程序编译后的二进制机器指令
  • 所有函数代码、程序执行语句

特点

  1. 只读,不允许修改
  2. 共享:多个进程运行同一程序,共用一份代码区
  3. 程序运行期间全程存在,程序结束才释放

2. 全局区

存放内容

  • 全局变量
  • 静态局部变量 static
  • 字符串常量、const 全局常量

特点

  1. 程序一运行就分配,程序结束才释放
  2. 生命周期贯穿整个程序
  3. 所有函数都可以访问全局区变量

示例:全局变量与静态变量

#include <iostream>
using namespace std;

// 全局变量——存放在全局区
int g_a = 10;

void func()
{
    // 静态局部变量——存放在全局区
    static int s_b = 20;
    s_b++;
    cout << s_b << endl;
}

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

静态变量只会初始化一次,生命周期和程序一样长。


3. 栈区(重点)

存放内容

  • 局部变量
  • 函数形参
  • 函数调用时的现场信息

特点

  1. 由系统自动分配、自动释放
  2. 函数执行完毕,栈上变量立刻销毁
  3. 空间有限,不能开大数组、大对象

栈区致命规则

不要返回局部变量的地址局部变量在函数结束后立刻销毁,地址变成野指针。

错误示例:

int* getAddr()
{
    int a = 10;   // 局部变量,在栈区
    return &a;    // 错误!函数结束a销毁,返回野指针
}

4. 堆区(重点)

存放内容

  • 程序员用 new 手动开辟的内存
  • 动态数组、动态对象

特点

  1. 由程序员手动开辟、手动释放

    • 开辟:new
    • 释放:delete
  2. 生命周期由程序员决定,不主动释放会内存泄漏

  3. 空间非常大,适合存放大数据、大数组

堆区开辟与释放基础用法

int main()
{
    // 在堆区开辟一个int内存
    int *p = new int(100);  

    cout << *p << endl;

    // 手动释放堆内存
    delete p;   
    p = nullptr; // 置空,防止野指针

    return 0;
}

四、栈区 vs 堆区 核心对比

表格

区域分配方式释放方式生命周期空间大小适用场景
栈区系统自动系统自动函数结束即销毁局部变量、形参
堆区程序员 new程序员 delete手动控制极大大数据、动态内存、对象

记住:临时变量放栈,长久使用、大数据放堆。


五、new /delete 动态内存操作

1. 开辟单个数据

// 开辟并初始化为10
int *p = new int(10);
delete p;

2. 开辟数组

// 开辟长度为5的int数组
int *arr = new int[5];

// 释放数组要加 []
delete[] arr;

3. 内存泄漏原因

  1. new 之后忘记 delete
  2. 指针重新赋值,原来堆内存找不到了,无法释放

示例内存泄漏:

int *p = new int(10);
p = new int(20);  // 原来的10没人释放,泄漏
delete p;

六、各区变量生命周期总结

  1. 代码区:程序启动到结束
  2. 全局区:程序启动到结束
  3. 栈区:函数调用开始 → 函数执行结束立即销毁
  4. 堆区:new 开辟 → 程序员 delete 释放

七、常见内存坑与避坑

  1. 返回局部变量地址 → 野指针、程序崩溃
  2. 堆内存 new 不 delete → 内存泄漏
  3. delete 后不置空 → 变成野指针
  4. 栈上定义超大数组 → 栈溢出崩溃
  5. 数组堆释放不用 delete [] → 内存错乱

八、今日学习总结

  1. 内存四区:代码区、全局区、栈区、堆区
  2. 代码区:只读、存函数指令
  3. 全局区:全局变量、static 静态变量,程序全程有效
  4. 栈区:局部变量、形参,系统自动分配自动释放,不能返回局部地址
  5. 堆区:new 手动开辟、delete 手动释放,空间大、生命周期可控
  6. 分清栈和堆,是看懂指针、面向对象、内存泄漏的底层基础

✍️ 下节预告

下一篇将学习 C++ 最常用的核心语法之一:引用全解,包含:引用的基础概念与语法、引用三大强制规则、引用的底层本质(常量指针)、引用做函数参数、引用做函数返回值、常引用的用法与作用,掌握引用可以替代指针简化代码、提高程序安全性,为后续面向对象编程、运算符重载打下关键基础。