## 内存泄漏 / 内存碎片 ## 判别规则(核心,唯一要记的) - **判别泄漏**:`malloc/calloc/realloc` 必须找到对应的 `free`,且覆盖**所有代码路径**(提前 return 也算);指针被覆盖前先 free 原来的 - **判别碎片 vs 泄漏**:可用内存总量持续减少 = **泄漏**;总量没少但大块申请失败 = **碎片** 一句话:**"配对不齐是泄漏,洞不齐是碎片;泄漏少总量,碎片乱布局。"** ## 抽象描述(一句话本质) 内存泄漏 = 申请了不释放(该还没还,总量变少);内存碎片 = 释放了但空间不连续(还了但乱,总量够却申请不到大块)。泄漏是"忘还",碎片是"还了但乱"。 ## 正反例(建立直觉) - **正例1(基本泄漏)**:`void f(){ int *p = malloc(100); /* 忘 free */ }` → 每次调用泄漏 100 字节。查法 = malloc/free 一一配对 - **正例2(隐蔽泄漏)**:`int *p = malloc(100); p = malloc(200);` → 第一个 100 字节地址被覆盖丢了,没法 free → 泄漏。指针被重新赋值前必须先 free - **正例3(碎片)**:反复 malloc/free 不同大小 → 中间留洞,总量够但每洞太小 → 大块申请失败 - **反例1(路径不匹配)**:`int *p = malloc(100); if (flag) return; free(p);` → 提前 return 漏了 free,也是泄漏(配对要覆盖所有路径) - **反例2(碎片≠泄漏)**:碎片时内存总量没少,只是不连续;泄漏时总量实实在在变少 ## 易混对比 | | 内存泄漏 | 内存碎片 | | ---- | ------------------------ | ------------------------------ | | 本质 | **该还没还**(总量变少) | **还了但乱**(总量够、不连续) | | 现象 | 可用内存持续减少 | 大块分配失败 | | 原因 | malloc 不配对 free | 随机分配/释放不同大小 | | 查法 | malloc/free 配对检查 | 看分配失败时空闲块分布 | | 治理 | 配对、RAII、内存池归还 | 合并算法、固定大小块、内存池 | ## 变体验证(3 题,全过=学会) 1. `int *p = malloc(100); p = malloc(200);` → **泄漏**(第一个 100 字节地址被覆盖丢失,没法 free) 2. 陷阱题:malloc/free 换成内存池(固定大小块)→ **碎片问题解决**(固定大小原样复用),但**泄漏没解决**(还是要靠归还配对) 3. 陷阱题:嵌入式长期运行 → 碎片是**渐变后突发**(跑很久某次大申请突然失败);泄漏是**线性累积、可监测**(剩余内存持续减少) ## 口述要点(面试怎么讲) - **结论先行**:泄漏少总量(该还没还),碎片乱布局(还了不齐) - **嵌入式为什么特别致命**:PC 有虚拟内存(MMU)把物理散页翻译成连续虚拟地址,外部碎片被掩盖 + 内存大可换页,所以 PC 主要栽在泄漏;嵌入式**重启代价高(产品不能随便重启)、内存小、程序不退出所以泄漏永久累积、崩溃只能看门狗复位带数据丢失** - **检测手段**:① FreeRTOS `xPortGetFreeHeapSize()` 看剩余堆反复减少 = 泄漏 ② 包装记账(my_malloc/my_free 计数器,申请数−释放数 ≠ 0 即泄漏)③ 记录调用点(带 `__FILE__`/`__LINE__` 打印谁申请的)④ PC 开发期 valgrind / AddressSanitizer 预检 - **治理碎片**:① 合并相邻空闲块(coalescing)② 固定大小内存池(内存分区)③ best-fit / first-fit 分配策略 ④ 减少大小混杂的小对象频繁分配 - **易错点**:提前 return 漏 free;把悬垂(用了已释放)和泄漏(该还没还)混为一谈 ## 关系网络 | 相邻概念 | 和本主题的关系 | 孤立理解会犯的错 | | --------------- | --------------------------------------------------- | ------------------------------------ | | 堆 vs 栈 | 泄漏/碎片全发生在堆——栈天然没有这两个问题 | 以为栈也有泄漏 | | 内存池 | 治理碎片的第一手段:固定大小块 + 归还配对 | 以为池子能顺带治好泄漏 | | 野指针 | 悬垂(用了已释放)vs 泄漏(该还没还)——一对反向错误 | 把悬垂和泄漏混为一谈 | | FreeRTOS 堆管理 | heap_1~heap_5:不同策略对应不同碎片/泄漏特性 | 以为 FreeRTOS 内存和裸机 malloc 一样 | ## 学习日期 2026-08-03 --- _每主题一页,复习时只翻本目录。_