垃圾回收GC
垃圾回收(GC)
1. 什么是垃圾回收(GC)
基于 Flash 不能覆盖写(需先擦除),写操作单位是 Page,而擦除单位是 Block,无法像传统磁盘那样直接更新原地数据的物理特性,FTL 会采取写入新位置+标记旧数据为无效的策略,这会产生大量的“无效页”,GC的目的就是识别这些无效页所处的块,迁移有效数据并回收无效快,形成新的空块供后续写入。
2. FTL GC 的流程
2.1 触发条件
触发条件类型 | 描述 |
---|---|
写入前检查 | 写入操作发现没有空页 |
定时后台回收 | 周期性清理空间,提升寿命 |
空闲块低水位 | 可用Block数低于某一阈值 |
主动触发 | 压力测试、工厂测试等 |
2.2 选择回收块
策略名 | 描述 | 优点 | 缺点 |
---|---|---|---|
Greedy(贪婪) | 选择无效页最多的块 | 简单、实现快 | 易磨损集中 |
Cost-Benefit | 计算一个代价函数,入(无效页数×权重)/总写次数 | 磨损均衡 | 算法复杂 |
Age-Based | 优先选择“老旧”块(如未写入时间长) | 有助于热/冷数据分离 | 不适合频繁写 |
FIFO | 按写入顺序回收旧块 | 适合线性写场景 | 对碎片容忍差 |
Wear Leveling GC | 结合写次数,优先清除低擦写块 | 均衡寿命 | 复杂度较高 |
2.3 有效数据搬移
一旦选中 victim block:
- 遍历其所有页
- 找到标记为“有效”的数据页
- 复制到空闲块中的空页位置
- 更新逻辑地址到新物理页的映射(L2P)
- 有效数据:浅灰色方块A、B、C、D、E、F、G
- 无效数据:深灰色方块A、B、C、D、E、F、G
2.4 擦除 victim block
当有效数据搬移完毕,该块中剩余的均为无效数据:
- 执行物理 NAND 擦除命令
- 将该 Block 回归到 Free Block List
3. GC 分类
类型 | 描述 | 触发时机 |
---|---|---|
前台GC | 主线程阻塞时触发GC | 写前无可用页 |
后台GC | 空闲时间触发GC | 用户写入少时 |
增量GC | 每次回收少量块,逐步进行 | 减少延迟峰值 |
紧急GC | Flash空间几乎耗尽时强制触发 | 写阻塞严重时 |
4. 优化策略
策略 | 说明 |
---|---|
合理 Victim 策略 | 使用 Cost-Benefit 和 Age-Based 提升效率 |
增量GC | 减轻突发 GC 带来的系统卡顿 |
Hot/Cold 分离写 | 热数据集中写,冷数据集中 GC,提升效率 |
数据对齐写入 | 避免跨页写造成有效页碎片 |
5. 判断有效/无效数据
方式:判断数据所在的闪存块的 LBA 与映射表对应的物理地址是否一致来决定有效/无效数据
将数据写入闪存时,会额外打包一些元数据,它记录着该笔数据所对应的逻辑地址、时间戳等相关信息。
当固件把数据读取出来,就获得了该笔数据对应的 LBA,然后查找映射表找到与该 LBA 对应的物理地址,如果物理地址与该闪存块的 LBA 一致,说明是有效数据,否则该数据就是无效的。进行垃圾回收时不需要对无效数据进行搬移。
把源闪存块的数据全部读出来的缺点是垃圾回收做的慢,不管数据是否有效都要读出来,然后还需要查找映射表来判断该笔数据是否有效。
有一种解决办法就是在L2P映射表外,再维护一张 P2L 表,该表记录每个闪存块写入的 LBA,该 P2L 数据写在该闪存块某个位置。当回收该闪存块时,首先把该P2L表加载上来,然后根据上面的LBA,依次查找映射表以决定该数据是否有效,有效数据会被读上来,然后重新写入。
6. 直写和 Copy-Back
6.1 直写
6.1.1 定义:
FTL 最基本的写策略,将写请求直接写入闪存的物理页,不经过任何缓存也不使用闪存的内部拷贝命令。
6.1.2 流程(全页写为例)
- 步骤1:发送逻辑地址(LBA)和数据(如4KB全页数据)。
- 步骤2: FTL 查询映射表(逻辑地址→物理地址):
- 若为新逻辑页(未分配过物理页),分配一个空闲物理页(P);
- 若为已有逻辑页(已映射到物理页 P_old),由于闪存不能覆盖写, 需分配新物理页(P_new)。
- 步骤3:向闪存发送写命令(Program),将数据写入 P_new。
- 步骤4:更新映射表,将逻辑地址映射到P_new,并标记P_old为无效 页(Invalid Page)。
- 步骤5:返回写成功信号给主机。
6.2 Copy-Back
6.2.1 定义
FTL 利用闪存芯片的 Copy Back 命令优化写操作,将一个物理页的全部数据从源页拷贝到目标页,且无需将数据读取到主机,完全由闪存内部完成。
6.2.2 流程
假设主机要修改逻辑页 L 对应的物理页 P_old 的后 1KB 数据(新数据为 D_new_part):
- 步骤1:发送逻辑地址 L 和部分数据 D_new_part(1KB)。
- 步骤2: FTL 查询映射表,找到L对应的旧物理页P_old(数据为D_old,4KB)。
- 步骤3:分配新物理页 P_new(空闲页)。
- 步骤4:向闪存发送 Copy-back 命令,将 P_old 的 D_old 内部拷贝到 P_new(无需读取 D_old)。
- 步骤5:向闪存发送写命令,将D_new_part 写入 P_new 的对应位置(如 后1KB),覆盖原 D_old 的后1KB,得到合并后的数据(前 3KB 为 D_old,后 1KB 为 D_new_part)。
- 步骤6:更新映射表,将 L 映射到 P_new,标记 P_old 为无效页。
- 步骤7:返回写成功信号。
6.3 TLC 颗粒采用“SLC 模式缓存+Copy-Back”
TLC 的慢写入速度、短寿命和高误码率是其致命缺陷,需通过 FTL 优化(SLC模式缓存+Copy-Back)弥补,核心目标是提升写入性能、降低写放大(Write Amplification)和延长寿命。
6.3.1 SLC 模式缓存:解决 TLC 写入速度慢的问题
TLC 的写入速度远慢于需求(TLC 的物理写入速度仅约100-200 MB/s)。SD 卡中的 TLC 颗粒会划分一部分物理块作为 SLC 缓存(通常占总容量的1%-5%),用模拟 SLC 模式(将 TLC 的8个电压等级简化为2个,每个单元存 1bit)工作。
- SLC 模式的优势: 写入速度快(约是 TLC 的3-5倍)、可靠性高(误码率低,无需复杂 ECC)。
- 流程: 主机的写请求(尤其是小请求,如1KB)先写入 SLC 缓存块(用 SLC 模式),快速返回“写成功”给主机(延迟低)。之后,FTL 在后台将 SLC 缓存块中的数据合并为全页(如4KB),再迁移到 TLC 数据块。
6.3.2 Copy-Back:解决 TLC“写放大高”和“功耗高”的问题
SD 卡的容量小(如 32GB-512GB),TLC 的寿命短(擦除次数少),需严格控制写放大(实际写入闪存的数据量/主机请求写入的数据量)。写放大越高,寿命消耗越快。
- 小文件的问题:SD卡 的使用场景多为小文件写入(如相机的照片、手机的应用数据),若直接写 TLC 块,每个小文件需分配一个新页(4KB),导致无效页增多(旧页的未修改部分无法覆盖写),写放大高(如 1MB 文件分10次写,写放大 = 4KB × 10 ÷ 1MB = 4)。
- Copy-Back 的优化:
- 合并小文件:将 SLC 缓存中的小文件合并为全页(4KB),减少无效页数量;
- 内部迁移:用 Copy-Back 命令将 SLC 缓存中的全页数据内部拷贝到TLC数据块。
- 效果:
- 写放大降低:合并后的全页写仅产生1个无效页(SLC缓存中的页),写放大=4KB/4KB=1(最优);
- 功耗降低:内部拷贝(闪存内部总线)比主机接口(如SDIO)传输更省电(减少主机的等待时间和数据传输功耗);
- 不影响主机使用:后台迁移,主机(如相机)无需等待,继续拍摄。
6.3.3 示例:TLC SD 卡的写入流程(相机连拍)
假设相机拍摄10张1MB的照片(每张分10次 100KB 写入):
- 步骤1:相机的10次 100KB 写入请求先写入 SLC 缓存块(用模拟 SLC 模式,写入速度快,延迟低);
- 步骤2:当SLC缓存块的有效数据达到全页(4KB),控制器分配一个 TLC 数据块的空闲页;
- 步骤3:发送 Copy-Back 命令,将 SLC 缓存中的 4KB 数据内部拷贝到 TLC 数据块(无需相机参与,减少相机的等待时间);
- 步骤4:重复步骤2-3,直到10张照片的所有数据都迁移到 TLC 数据块;
- 结果:相机连拍时无卡顿(SLC 缓存快速接收数据),写放大=1(合并后的全页写),寿命消耗慢(写放大低)。
7. GC、直写、Copy-Back 的协同关系
7.1 三者的核心作用
- 直写:将主机写请求直接写入闪存物理页,不经过缓存。若逻辑页已映射到旧物理页,需分配新页,旧页标记为无效页(Invalid Page)。
- Copy-Back:闪存的内部拷贝命令,将源页数据直接拷贝到目标页(无需主机读取)。主要用于部分写优化(合并旧数据与新数据)和 GC 时的有效页迁移。
- GC:回收无效页的过程。当块中的无效页比例超过阈值(如70%),需将块中的有效页(Valid Page)迁移到新块,再擦除旧块(释放空间)。
7.2 三者的核心关系
7.2.1 直写:无效页的“生产者”,触发GC
任何写操作(无论直写还是Copy-Back)都会产生无效页(旧页无法修改,只能标记为无效)。但直写的无效页“开销”更大。
- 部分写场景:若修改逻辑页的 1KB 数据(页大小4KB),直写需读取旧页的4KB数据,合并新数据后写入新页 4KB。此时,旧页的 4KB 全部无效,新页的 4KB 有效,无效页数据量=4KB,主机传输量=4KB(旧)+4KB(新)=8KB。
- 全页写场景:若写入4KB全页数据,直写只需分配新页,旧页标记为无效。此时,无效页数据量=4KB,主机传输量=4KB(新)(无旧数据读取)。
直写的无效页产生率(无效页数据量/写入数据量)在部分写场景下极高(如8KB/1KB=8),导致无效页快速积累。当块中的无效页比例超过阈值(如70%),GC被触发(必须回收空间,否则无空闲页可用)。
7.2.2 Copy-Back:无效页的“优化者”,降低GC压力
Copy-Back的核心价值是减少无效页的“开销”(数据传输量、写延迟),并优化GC的有效页迁移效率。
优化部分写的无效页“开销”: 部分写时,Copy-Back 无需读取旧页数据,而是通过内部拷贝将旧页数据(4KB)复制到新页,再写入新数据(1KB)。此时:
- 无效页数据量:与直写相同(4KB,旧页无效);
- 主机传输量:仅 1KB(新数据),比直写的8KB减少7/8;
- 结论:Copy-Back不减少无效页数量,但减少了无效页产生的“代价”(传输量、延迟),间接降低了GC的“触发频率”(因为无效页的“代价”小,系统可容忍更多无效页)。
7.2.3 GC:无效页的“回收者”,依赖直写与Copy-Back的“输入”
GC的效率取决于两个关键因素:
- 无效页比例:块中的无效页比例越高,有效页越少,迁移量越小,GC 效率越高(如无效页比例70%,有效页比例30%,迁移 30% 的页即可擦除块)。
- 有效页迁移速度:迁移速度越快,GC 停顿时间越短,系统稳定性越好。
7.3 三者的协同价值
直写、Copy-Back 与 GC 的协同,最终实现了 FTL 的三大核心目标:
- 优化写性能:\直写用于全页写(简单高效),Copy-Back 用于部分写(减少传输量、延迟),使写延迟低。
- 降低写放大:Copy-Back 减少了部分写的“无效页开销”(传输量),GC通过回收无效页减少了“无效页积累”,使写放大(实际写入数据量/主机请求数据量)降低(如部分写的写放大从8降至1.25)。
- 延长闪存寿命:写放大降低意味着闪存的擦除次数减少(每擦除一次块,寿命消耗一次),从而延长闪存寿命。
高效),Copy-Back 用于部分写(减少传输量、延迟),使写延迟低。
- 降低写放大:Copy-Back 减少了部分写的“无效页开销”(传输量),GC通过回收无效页减少了“无效页积累”,使写放大(实际写入数据量/主机请求数据量)降低(如部分写的写放大从8降至1.25)。
- 延长闪存寿命:写放大降低意味着闪存的擦除次数减少(每擦除一次块,寿命消耗一次),从而延长闪存寿命。