C++ 进阶笔记:栈内存 vs 堆内存

C++ 进阶笔记:栈内存 vs 堆内存

一、 内存的基本概念

在 C++ 程序运行时,RAM(内存)会被划分为多个区域,其中最令开发者关心的两个区域就是 栈 (Stack)堆 (Heap)

  • 物理位置:两者都在 RAM 中,物理本质没有区别。
  • 分配逻辑:区别在于操作系统和编译器如何管理这两块区域。

二、 栈内存 (Stack) ------ 极致的速度

1. 工作原理

栈的工作方式类似于"叠盘子"。它有一个 栈指针 (Stack Pointer),分配内存只需移动该指针。

  • 分配:向下移动指针(在大多数系统上地址由高到低)。
  • 释放:向上移动指针。

2. 特点

  • 生命周期 :由作用域 {} 自动管理。一旦离开大括号,内存立即释放(Pop)。
  • 速度 :极快。在汇编层面通常只需 一个 CPU 指令 (如 sub esp, 4)。
  • 局限性 :空间有限(通常为 1MB - 2MB)。如果分配过大(如 int arr[1000000]),会导致 栈溢出 (Stack Overflow)

三、 堆内存 (Heap) ------ 灵活性与代价

1. 工作原理

堆是一块巨大的空闲存储区。

  • 分配 :使用 new 关键字。系统会查找 空闲列表 (Free List) 来寻找足够大的连续空间。
  • 释放 :必须手动调用 delete(或使用智能指针),否则会导致 内存泄漏

2. 特点

  • 生命周期:由程序员手动控制,可以跨越函数作用域存在。
  • 速度 :较慢。因为 new 涉及到繁琐的"簿记"工作,甚至需要向操作系统申请更多物理内存。
  • 优势:空间几乎仅受物理内存限制,适合存储大数据(如数据库缓冲区、大型纹理)。

四、 汇编与底层对比 (Debug 模式下)

Cherno 在视频中对比了两者在底层的真实开销:

  • 栈分配 (int v = 5)
    直接将值存入对应的内存地址。指令极其简单。
  • 堆分配 (int v = new int(5)) *:
    1. 调用 operator new
    2. 内部调用 malloc
    3. 执行复杂的查找空闲空间、记录分配大小等逻辑。
    4. 最终才返回指针。

五、 核心结论:如何选择?

  1. 默认优先用栈:只要对象不需要在函数结束后存活,且大小不是特别巨大,永远优先选择栈分配。
  2. 必须用堆的情况
    • 对象需要在函数结束后继续存在(需手动控制生命周期)。
    • 分配的数据量非常大(超过几百 KB 或 MB 级别)。
    • 对象的具体大小在编译时无法确定,且可能非常大。

六、 进阶思考

  • 内存池技术 (Memory Pooling) :为了结合"堆的容量"和"栈的速度",数据库通常会在启动时在堆上 new 一大块空间,然后自己在内部模拟栈的分配逻辑(手动移动指针)。这被称为"自定义内存分配器"。
相关推荐
郝学胜-神的一滴8 小时前
Qt 高级编程 042:进度条从入门到自定义美化
开发语言·c++·qt·软件开发·用户界面
啦啦啦啦啦zzzz8 小时前
5种IO模型
运维·服务器·网络·c++
鸿芯微控科技8 小时前
压电纳米定位分辨率怎么测?噪声、带宽、最小可检测位移与Python分析
开发语言·python·噪声分析·压电执行器·纳米定位·位移测量
呱呱巨基8 小时前
Docker 基础概念学习
linux·c++·学习·docker
@小匠8 小时前
Spring Boot Nacos绑定 Map 时中文 key 导致启动失败:一次从复现到源码的排查实录
java·开发语言·前端
Knight_AL8 小时前
Lombok @Builder 踩坑:build() 前后对象类型不一样
android·java·开发语言
神明不懂浪漫9 小时前
【第五章】队列
开发语言·数据结构·经验分享·笔记·算法
吃好睡好便好9 小时前
MATLAB仿真框图3
开发语言·matlab·仿真·simulink
-银雾鸢尾-9 小时前
C#中的反射关键类-Type
开发语言·c#
大黄说说9 小时前
Java 与 Kotlin 混合开发避坑指南:老项目平滑迁移 Kotlin 实操手册
java·开发语言·kotlin