Skip to content

进程内存布局:虚拟内存 / 堆 / 栈

一、进程虚拟地址空间(64 位 Linux x86-64)

0x7FFF FFFF FFFF ┌──────────────────┐ 高地址(往下长)
                 │   栈 Stack        │ 向下生长(高→低),含局部变量/函数帧
                 │   ↓               │
                 │  (空洞/共享区)    │ 共享库 mmap 段
                 │   ↑               │
                 │   堆 Heap         │ 向上生长(低→高),malloc/new
                 │  .bss (未初始化全局/static)│
                 │  .data(已初始化全局/static)│
                 │  .rodata(只读常量)         │
                 │  .text(代码段)   │
0x0000 0000 0000 └──────────────────┘ 低地址

关键概念

  • 这只是虚拟地址空间,页表映射到物理页;未访问的页不实际占物理内存(按需调页)。
  • .text(代码)、.data(已初始化全局/静态)、.bss(未初始化全局/静态,不占文件只占内存)、.rodata(字面量常量)、堆、栈、共享库 mmap。

二、C++ 的内存分区(教材口径)

  1. 代码区(text):函数代码,只读。
  2. 全局/静态存储区(data+bss):全局变量、静态变量——程序启动分配、结束释放。
  3. 常量区(rodata / 也可能是 text 后段),只读:字符串字面量等。
  4. 栈区:局部变量、函数参数、返回地址——编译期已定大小,随调用分配释放,速度快,有大小上限(Linux 默认栈 8MB ulimit -s)。
  5. 堆区:程序员管理(new/malloc),由低向高增长,慢、易碎片。

常混淆:只读常量直接量一般归于常量区(可在 data/rodata);很多人把它并入「全局区」。面试可答「广义上全局常量在 data 只读段」。重点讲清楚 栈 vs 堆 的特征。

三、栈 vs 堆 对比

维度栈 (Stack)堆 (Heap)
分配编译器自动(函数帧)程序员 new/malloc 手动
方向高地址向低地址(向下)低地址向高地址(向上)
速度极快(移动栈指针)慢(找空闲块/系统调用)
生命周期函数作用域结束即释放需手动释放或用 RAII
大小限制有(Linux 8MB,可 ulimit)可到虚拟内存上限(通常很大)
碎片无(后进先出规整)有(malloc 分配/释放不规整)
多线程每线程独立栈进程内所有线程共享堆(需同步)
越界风险栈溢出(递归过深)泄漏 / use-after-free / 野指针
谁能返回栈上数组不能把局部地址当返回值给上层长期使用(悬垂)可(用智能指针管理)

记忆点

  • 栈 = 快 + 自动 + 有上限 + 连续规整;堆 = 灵活 + 大 + 需管理。
  • 线程独立栈:递归深度过大 → 栈溢出(crash):经典题「深递归爆栈/段错误」。
  • 栈对象:通常小而生命周期短、或 RAII 包裹堆资源。

四、函数调用压栈

调用 f(a,b)

  1. 参数按调用约定入栈(多数 x86-64 ABI:前 6 整数参数用寄存器,多的才入栈)。
  2. 压入返回地址
  3. call 跳到 f:保存栈帧指针(rbp),分配局部变量空间(rsp 调整)。
  4. 返回时恢复,栈指针回弹(栈即「后进先出」,释放即指针回弹,天然无碎片)。

五、高频题

Q1. 栈空间 vs 虚拟内存大小;为什么递归太深会栈溢出?

每个线程栈默认约 8MB,递归每层消耗帧 → 深度过大爆栈(Segmentation fault)。规避:尾递归/改循环/加大线程栈(pthread_attr_setstacksize)/把大结构放堆。

Q2. 堆为什么比栈慢?

分配要经过用户态 free-list 查找 + 可能系统调用 brk/mmap;且有锁、缓存不友好 (heap 对象分散导致 cache miss 高于连续栈帧)。栈通常就在当前 cache line、只改指针。

Q3. 全局对象构造/析构顺序?

构造:定义序(跨翻译单元顺序未定——知名坑「Static Initialization Order Fiasco」,可用局部 static / Meyers Singleton 规避)。析构:构造逆序。

Q4. malloc 返回的地址是物理地址吗?

不是,是虚拟地址;由 OS+页表映射,程序员不感知物理地址。

C++ 面试八股 · VitePress 版