10.内存分配方式.md 4.2 KB

内存分配方式

判别规则(核心,唯一要记的)

  • 看声明方式定区:全局/static → 静态区(程序期,系统收);函数内局部(无 static)→ 栈(函数期,系统收);malloc/free → 堆(程序员管)
  • 谁管释放是关键:只有堆要程序员负责;栈和静态区都系统自动回收

一句话:"全局住酒店(静态区),局部住民宿(栈),malloc 自己买房(堆)——前两个店家收房,最后一个自己管。"

抽象描述(一句话本质)

C 内存分三区——静态区(程序期)、栈(函数调用期)、堆(malloc 到 free)。每个变量必答三连问:住哪?活多久?谁收?

正反例(建立直觉)

  • 正例1(静态区)int g; / static int s; → 程序启动分配、结束回收,自动清零,活整个程序期
  • 正例2(栈)void f(){ int x = 5; } → 调用时分配、返回自动销毁,快但量小(KB 级)
  • 正例3(堆)int *p = malloc(100); → malloc 分配、free 手动释放,不 free 就泄漏
  • 反例1:返回栈地址 → 悬垂指针(函数返回栈销毁,地址变废纸)
  • 反例2:malloc 后忘 free → 内存泄漏

易混对比

静态区
谁分配 程序启动 函数调用时 malloc
生命周期 整个程序期 函数调用期间 malloc → free
谁管释放 系统自动 系统自动 程序员
大小/速度 固定,快 小(KB 级),很快 大,慢(要查找空闲块)
自动初始化 ✅ 清零 ❌ 垃圾值 ❌ 垃圾值

陷阱:函数内 static int x;静态区不是栈(static 改的是存储期)。

变体验证(3 题,全过=学会)

  1. const char *s = "hello"; → 字符串字面量在只读数据区(静态区一族),不能修改
  2. 陷阱题:全局 int g[10]; 元素默认全是 0;函数内 int l[10];垃圾值(静态区自动清零 vs 栈不初始化)
  3. 陷阱题:void f(){ int *p = malloc(100); } 函数返回后 → 指针没了,堆内存还占着没人能 free → 内存泄漏

口述要点(面试怎么讲)

  • 结论先行:三区(静态区/栈/堆)+ 谁管释放(只有堆归程序员)
  • 为什么栈快堆慢:栈分配 = 移动栈指针 SP,一条指令完成;堆分配 = 遍历空闲块链表找合适块,可能要分裂/合并,慢且时间不确定
  • 嵌入式为什么不推荐 malloc:① 内存小 + 碎片化(反复 malloc/free 后大块申请失败)② 分配时间不确定,破坏实时性 ③ 泄漏后果重、重启代价高。替代:静态分配、内存池、FreeRTOS 的 heap_1~heap_5
  • 栈溢出:栈大小有限。每调用一层函数就压一帧(局部变量+参数+返回地址),递归/深嵌套层层压 → 栈耗尽 → 覆盖相邻内存 → HardFault。RTOS 里用 HighWaterMark 检测剩余栈
  • 易错点:函数内 static 变量住静态区不是栈;栈不碎片、堆碎片

关系网络

相邻概念 和本主题的关系 孤立理解会犯的错
程序分段 三区放一起讲:代码段/数据段/BSS/堆/栈——本题是三区的微观版 以为堆栈是"段"(实际是动态区)
堆 vs 栈 谁分配、谁回收、速度、碎片——三区里最常单独拷的对比 以为栈也像堆一样会碎片化
static static 局部 = 静态区,不是栈 以为函数内声明就住栈
内存碎片 malloc/free 反复 → 堆碎片化 以为碎片只有大小问题,不关心分配失败

学习日期

2026-08-03


每主题一页,复习时只翻本目录。