一文读懂 Flash 底层原理
1、Flash 的硬件科普
从口袋里的智能手机、笔记本电脑,到数据中心的服务器,Flash 已经成为现代数字世界的基础存储介质。无论是 U 盘、SSD,还是手机中的 eMMC、UFS,其核心本质上都是 Flash 存储芯片。
与传统内存或机械硬盘不同,Flash 最大的特点是断电不丢数据(非易失性)。但这种能力的代价是:它无法直接覆盖写入,而必须遵循“先擦除,再写入”的规则。这也进一步引出了垃圾回收、磨损均衡等一系列复杂机制。
要理解这一切,我们必须回到最底层——Flash 的最小物理单元:浮栅晶体管(Floating Gate Transistor)。
1.1 什么是浮栅晶体管
浮栅晶体管可以看作是一个“带记忆的开关”。在普通 MOS 晶体管的基础上,它多了一层关键结构——浮栅(Floating Gate)。
它的基本结构包括:
- 控制栅(Control Gate):外部施加电压的入口
- 绝缘层(Interpoly Oxide):隔绝电子
- 浮栅(Floating Gate):被绝缘层完全包裹,用来存储电子
- 隧穿氧化层(Tunnel Oxide):电子进出浮栅的“通道”(可以理解为一种特殊的绝缘层)
- 源极(Source) / 漏极(Drain):电流通路
- P-well(P型阱)
- 衬底(Substrate / Bulk):整个器件的“地基”,也是擦除时的关键电极

👉 关键点:
浮栅是一个完全电气隔离的“孤岛”,电子一旦进入,就不会自然流失,这就是“记忆”的来源。
需要注意的是,这种“不流失”是相对的:
- 电子仍然会通过氧化层发生极其缓慢的泄漏
- 受温度、时间、工艺缺陷等影响
- 最终可能导致数据丢失
但这个过程通常发生在年级别甚至更长时间尺度,因此在工程上可以视为“长期稳定”。
1.2 写入(Program)
写入操作的本质是:
👉 向浮栅中注入电子
典型过程包括:
- 在控制栅施加高电压
- 在源极/衬底配合电压
- 通过以下机制之一注入电子:
- Fowler–Nordheim 隧穿
- 热电子注入(Hot Electron Injection)

👉 特点:
- 是“单向操作”(只能加电子)
- 无法直接减少电子
因此:
❗ Flash 不能覆盖写,必须先擦除再写
1.3 擦除(Erase)
擦除操作的本质是:
👉 将电子从浮栅中移除
典型方法:
- 对衬底(Bulk)施加高电压
- 形成反向电场
- 通过 Fowler–Nordheim 隧穿将电子抽出
⚠️ 擦写寿命问题
浮栅依赖的隧穿氧化层并非无限耐用:
- 每次写入 / 擦除都会对氧化层造成损伤
- 长期循环会导致:
- 漏电增加
- 阈值电压漂移
- 最终导致存储失效
这就是 Flash 有限擦写寿命(P/E cycle) 的根本原因。
1.4 读取(Read)
读取操作不会改变数据,本质是:
👉 检测晶体管的阈值电压(Vth)
过程:
- 对控制栅施加读取电压
- 检测是否导通
导通 浮栅无电荷 → 1
不导通 浮栅有电荷 → 0
本质理解
- 浮栅无电荷 → 阈值电压低 → 易导通
- 浮栅有电荷 → 阈值电压高 → 难导通
👉 数据本质上是:
“阈值电压的不同状态”

2、NAND Flash 与 Nor Flash
Flash 的所有差异,本质都来自一个核心:
👉 存储单元在电路中的连接方式
2.1 NOR FLASH 的结构和特性
NOR FLASH 的结构原理图见图 1,可以看到每个 Bit Line 下的基本存储单元是并联的。这种结构使得每个存储单元(Cell)都可以被独立选通。
在读取数据时,FLASH 控制器只需对目标 Word Line 施加一个读取电压,被选中的存储单元(Cell)即可直接与 Bit Line 形成导通路径;而未选中的 Word Line 保持关闭状态,不参与当前读取操作。
此时,Bit Line 上的电流大小仅由该存储单元的导通状态决定:当浮栅中存有电荷时,阈值电压升高,晶体管难以导通,读出“0”;反之则读出“1”,从而实现对单个存储单元的读取。
由于这种并联结构,NOR FLASH 可以实现按位(Bit)随机访问(Random Access),并具有较高的读取速度,因此适合用于代码存储并支持直接执行(XIP)。


- 基本存储单元的并联结构决定了金属导线占用很大的面积,因此 NOR FLASH 的存储密度较低,无法适用于需要大容量存储的应用场合
- NOR FLASH 写入采用了热电子注入方式,效率较低,因此 NOR 写入速率较低,不适用于频繁写入场合
- NOR Flash 擦除依赖高压驱动的 FN 隧穿物理机制,叠加块擦除架构、复杂的操作流程(预编程+循环验证)及可靠性约束。擦除效率极慢
- 还有一个很重要的点,可以看到,3*8bit 的 NOR FLASH 是共用一个衬底的,这也决定,NOR FLASH 擦除只能按 “块” 擦除
最后来个小贴士:NOR FLASH 的中的 N 是 NOT,含义是 Floating Gate 中有电荷时,读出’0’,无电荷时读出’1’,是一种’非’的逻辑;OR 的含义是同一个 Bit Line 下的各个基本存储单元是并联的,是一种’或’的逻辑,这就是 NOR 的由来。
2.2 NAND Flash
NAND FLASH 的结构原理图见图 3,可以看到每个 Bit Line 下的基本存储单元(Cell)是串联的。因此,其读取机制与 NOR FLASH 有明显不同。
NAND 的读取单位是 Page。当需要读取某个 Page 时,FLASH 控制器会对该 Page 对应的 Word Line 施加一个读取参考电压(用于判断存储单元是否导通),同时对同一串中的其他所有 Word Line 施加一个较高的通过电压(Pass Voltage),以保证这些未选中的存储单元(Cell)全部处于导通状态,从而形成一条完整的电流通路。
此时,整条 Bit Line 是否导通,仅取决于被选中 Page 中对应存储单元(Cell)的状态:当浮栅中存有电荷时,阈值电压升高,单元关断,Bit Line 读出“0”;反之则读出“1”,从而实现整页数据的读取。
在同一 Word Line 的 Cell 称之为一页


- 由于串联结构的限制,NAND Flash 无法像 NOR Flash 那样对单个存储单元进行独立感测。读取某一 Cell 时,电流必须经过整条串联通路,其结果会受到其他 Cell 状态的影响。因此,在实际电路设计中,NAND 需要同时对一整行(Page)对应的所有 Bit Line 进行并行感测,并将数据一次性加载到页寄存器(Page Buffer)中。这也决定了 NAND 的读取以 Page 为基本单位,难以支持真正的位级随机访问,程序代码通常无法直接在 NAND 上执行(需先搬运到 RAM)。
- 在写入与擦除方面,NAND Flash 通过结构上的高度规则性,实现了更强的并行操作能力。例如,编程(Program)通常以整页为单位,对大量存储单元同时施加脉冲电压(如 ISPP 过程);擦除(Erase)则以块(Block)为单位,对整片区域统一施加电场完成电荷释放。相比之下,NOR Flash 更依赖逐点编程(如热电子注入),操作粒度更细但并行度较低。因此,从系统吞吐量角度来看,NAND 在写入和擦除效率上通常显著优于 NOR,更适合大规模数据存储场景。
2.3 关于 NAND FLASH 和 NOR FLASH 的读取问题
虽然 NOR 和 NAND 在硬件上都为每根 Bit Line 配备了 Sense Amp,但两者的电路拓扑决定了它们完全不同的读取逻辑。
Sense Amp(感测放大器/读出放大器)是位于存储阵列列边缘的关键电路,用于在读取操作期间将位线(Bit Line)上极微弱的电压变化或电流信号放大为逻辑“0”或“1”。它通常包含预充、感测和锁存功能,对于实现快速、高密度和低功耗的数据读取至关重要
NOR Flash:独立的“房间”,支持随机访问
NOR 采用的是并联结构。每个存储单元都有独立的电流通路,一端连着 Bit Line,一端连着地。
- 读取逻辑: 当你选中某一行(Word Line)时,每个 Cell 的状态是物理隔离的。
- 结果: 硬件可以只激活你需要的那一根 Bit Line 的 Sense Amp,直接读取那一个 bit。这就是 NOR 具备“随机访问”能力、延迟极低的根本原因。
NAND Flash:串联的“通路”,必须整页并行
NAND 采用的是串联结构。8 个甚至更多的 Cell 像糖葫芦一样串在一起,共享同一根 Bit Line。这就带来了一个核心问题:你无法在不惊动整条通路的情况下,单独探测某一个 Cell。
- 电路困境(串干扰):
- 假设我们要读取串联电路中第 1 个 Cell(Cell A)的数据。
- 动作: 硬件给 Cell A 施加读取电压,同时给同一条 Bit Line 上的其他 Cell(Cell B, C, D…)施加高压 Vpass,试图让它们导通变成“导线”。
- 真相: 电流从 Bit Line 下来,必须依次穿过 Cell A、Cell B、Cell C… 才能流向地。
- 误判风险: 此时,Bit Line 上的电流大小,不仅仅取决于 Cell A 的导通程度,还取决于后面那一串 Cell 的电阻之和!
- 如果同一条串上的 Cell D 刚好处于“截止”边缘,或者阈值电压偏高(即使给了 Vpass也没完全导通),它的电阻就会变大。
- 这会导致整条路的电流变小。
- Sense Amp 检测到电流变小,会误判:“哎呀电流这么小,肯定是 Cell A 截止了(也就是存了 0)”。
- 结果: Cell A 明明是 1,却因为你“邻居”的状态不好,导致你读错了。
解决方案:强制整页并行读取
为了消除这种“串干扰”带来的误判,NAND Flash 必须采用整页并行读取的策略:
- 同时激活: 控制器不能只读一根 Bit Line,而是必须同时激活这一页(Page)对应的所有 Bit Line 的 Sense Amp。
- 数据搬运: 硬件会将整页的数据(比如 4KB 或 8KB)一次性全部读出来,搬运到页寄存器中。
- ECC 校验与纠错: 这一步至关重要。因为是并行读取,控制器可以利用这一页中专门预留的冗余空间(Spare Area)来进行 ECC 校验。如果因为上述的“串干扰”导致个别 bit 翻转,ECC 算法可以利用整页数据的冗余信息将其纠正过来。
3、NAND Flash Layout
物理上的 NAND 页(Page),是指同一 NAND 块(Block)内、水平方向上共享同一个控制栅极(即字线 Word Line)的一组存储单元。一个 NAND 块由若干个页组成,若干个块构成一个平面(Plane),而平面最终组成了晶粒(Die)。每个存储芯片(Chip)内部则包含一个或多个晶粒。
以下是一个 2GB 闪存设备的示例,该设备被组织成 2048 个块。每个块包含 64 个页。这是 NAND Flash 进行擦除操作的基本单位

图中核心展示了数据读写的“搬运逻辑”,这里涉及两个关键角色:
- 橙色方块(存储阵列中的页): 这是数据的“长期居所”。它的大小为 2112 字节,被划分为 2048 字节的主数据区(存用户数据)和 64 字节的备用区(存 ECC 校验码等)。
- 蓝色长条(寄存器): 这是位于顶部的 页寄存器,相当于一个高速“装卸货站台”。它的大小与橙色页完全一致(2112 字节)。
为什么需要寄存器?
因为存储阵列(橙色)读写速度慢,无法直接跟上外部处理器的速度。所以,NAND Flash 规定数据必须整页搬运:
- 读取时: 先把橙色页里的 2112 字节数据,一股脑全部“吸”到上方的寄存器里,然后再慢慢通过串行接口输出。
- 写入时: 先把数据通过串行接口塞满寄存器,然后再一次性“灌”入橙色页中。
图中右侧的操作时序直观地反映了这一过程的代价:
- 读取(页加载): 约 25 µs。这是把数据从橙色阵列搬运到蓝色寄存器的时间。
- 编程(写入): 约 220 µs。这是把数据从寄存器写入阵列并锁定电子的时间。
- 擦除: 约 500 µs。这是清空整个块的时间。
4、特性总结
上面零零散散提到了一些 NOR Flash 和 NAND Flash 的特性,这里做一个总结。
| 核心维度 | NOR Flash | NAND Flash |
|---|---|---|
| 1. 设计初衷 | 代码执行 替代 ROM/EPROM,追求极致读取速度和随机访问。 |
海量存储 替代 HDD,追求极致存储密度和低成本。 |
| 2. 电路结构 | 并联架构 每个 Cell 独立连位线,像独立房间,互不干扰。 |
串联架构 多个 Cell 串连共享位线,像糖葫芦,存在串扰。 |
| 3. 读取机制 | 随机访问 直接寻址任意 Byte,想读哪里读哪里。 |
页读取 必须整页并行搬运到寄存器,无法只读 1 bit。 |
| 4. 关键特性 | 支持 XIP CPU 可直接在 Flash 内跑代码,无需搬运。 |
不支持 XIP 代码需先拷贝到 RAM 才能运行。 |
| 5. 读写速度 | 读快,写/擦慢 读:纳秒级 (ns) 写/擦:秒级 (s) |
读较快,写/擦快 读:微秒级 (µs) 写/擦:毫秒级 (ms) |
| 6. 可靠性 | 极高 误码率低,通常无需 ECC,几乎无坏块。 |
较低 有串干扰,必须有 ECC 校验 和 坏块管理。 |
| 7. 容量成本 | 低容量,高成本 单元面积大,外围电路复杂,密度难提升。 |
高容量,低成本 结构简单紧凑,3D 堆叠成熟,单位成本低。 |
| 8. 典型应用 | 存代码 BIOS、Bootloader、固件、汽车 ECU。 |
存数据 SSD、U 盘、手机存储、SD 卡、文件系统。 |
5、垃圾回收
5.1 异地更新
在深入讨论垃圾回收之前,我们需要先理解 Flash 存储数据的一个核心机制——异地更新。这是所有现代 Flash 管理系统(无论是 SSD 主控还是 YAFFS 文件系统)的基石。
5.1.1 为什么不能“原地”修改?
回顾一下我们在第 2 章讲到的 NAND Flash 物理特性:
- 写入单位小:按“页”(Page)写入,通常为4KB。
- 擦除单位大:按“块”(Block)擦除,一个块包含几十个页(如256KB)。
- 不可覆盖:这是最关键的一点。Flash只能将位从1变为0(写入),但要将0变回1,必须执行“擦除”操作。
这就带来了一个尴尬的局面:假设你只想修改一个文件中的 1 个字节,而这个文件存储在 Flash 的第 1 个页中。
- 你不能直接覆盖写入,因为该页已经有数据了(不是全 1 状态)
- 你也不能只擦除这 1 个页,因为 Flash 不支持按页擦除,只能擦除整个块。如果擦除整个块,该块内其他页的数据也会丢失
5.1.2 异地更新的流程
为了解决这个问题,Flash 控制器(或文件系统)采用了一种“只追加、不覆盖”的策略,即异地更新。当主机请求修改某个逻辑地址的数据时,硬件/软件会执行以下“狸猫换太子”的操作:
- 标记旧数据:将原来存放旧数据的物理页(Page A)在逻辑上标记为“无效”。注意,数据还在里面,但系统已经知道它过时了。
- 寻找新窝:在 Flash 的空闲区域(空闲页表)中,找一个新的、已擦除的物理页(Page B)。
- 写入新数据:将修改后的新数据写入 Page B。
- 更新映射表:更新 FTL(闪存转换层)或文件系统的映射表,将主机的“逻辑地址”指向新的“物理地址”Page B。
结果: 下次读取该数据时,系统会直接去Page B读取,完全忽略 Page A。
5.1.3 带来的后遗症
异地更新虽然完美解决了“修改难”的问题,让写入速度极快(不需要先擦除),但它留下了一个严重的隐患:Flash 上会充斥着大量标记为“无效”的旧数据页。
如果不清理这些垃圾,空闲块很快就会耗尽,系统将无法写入任何新数据。这就引出了我们下一章的主角——垃圾回收。
5.2 垃圾回收(Garbage Collection, GC)
5.2.1 GC的核心逻辑
GC 的任务不仅仅是删除数据,更是要腾出完整的空闲块。因为 Flash 写入必须使用已擦除的块,所以 GC 的工作流程通常如下:
- 选择受害者:GC 算法会扫描所有块,挑选出一个包含最多“无效页”的块作为回收目标(通常称为“脏块”)。
- 数据搬家:在擦除这个脏块之前,GC 必须先检查里面是否还有有效页(即最新的数据)。如果有,必须先将这些有效数据读取出来,并复制到新的空闲块中。
- 更新映射:数据搬走后,必须更新地址映射表,告诉系统:“那个数据搬家了,去新地址找它”。
- 擦除旧块:确认有效数据都已安全迁移后,对整个脏块执行擦除操作。此时,这个块就变成了“空闲块”,可以重新使用了。
5.2.2 谁来做GC?(硬件FTL vs 软件FTL)
这里有一个重要的概念区分:谁来负责执行上述复杂的 GC 操作?
- 硬件 FTL(如 SSD、eMMC):
对于 SSD 或手机存储,主控芯片内部集成了一个复杂的闪存转换层(FTL)。操作系统只管发读写指令,完全不知道底层 Flash 的存在。底层的 GC、地址映射、坏块管理全由 SSD 主控在硬件内部透明地完成。 - 软件 FTL(如 YAFFS 文件系统):
对于直接连接 CPU 的“裸”NAND Flash,硬件不懂管理。这时,文件系统(如YAFFS)就必须充当“软件FTL”的角色。YAFFS 在软件层面实现了上述的 GC 逻辑,它扫描 OOB 区域(就是第 3 章节讲的 Page 中的“备用区”),维护内存中的映射树,并在后台线程中搬运数据、擦除块。
6、写放大(Write Amplification, WA)
在上一节 GC 的过程中,你可能发现了一个潜在的隐患:为了写入一点点新数据,我们可能被迫搬运了整个块中的旧数据。这种“额外的工作量”,就是写放大。
写放大是指主机实际请求写入的数据量与 Flash 物理介质实际写入的数据量之间的比值。
WAF=Flash物理实际写入总量主机逻辑请求写入量 WAF = \frac{\text{Flash物理实际写入总量}}{\text{主机逻辑请求写入量}} WAF=主机逻辑请求写入量Flash物理实际写入总量
理想情况下,WAF 应该等于1。但在现实中,由于 GC 的存在,WAF 通常远大于 1。
6.1 写放大的危害
寿命缩短:Flash 的寿命取决于擦写次数。写放大意味着你每写 1GB 数据,Flash 可能实际承受了 3GB 甚至更多的磨损。
性能下降:原本简单的写入,变成了“读取旧数据 -> 写入旧数据 -> 写入新数据”的复杂过程,导致 SSD 在使用一段时间后变慢。
7、磨损均衡
解决了垃圾回收和写放大的问题,我们还需要面对 Flash 的最后一个物理短板:耐久性有限。
如果仅仅依靠 GC 来管理空间,FTL 可能会倾向于总是使用最新的、刚擦除过的块(因为它们写入最快)。这会导致某些块被反复擦写,迅速达到寿命极限而损坏,而其他块却几乎没被使用。为了防止这种“贫富差距”过大,我们需要磨损均衡。
7.1 什么是磨损均衡?
磨损均衡是一种算法策略,旨在让 Flash 芯片上的每一个物理块都能均匀地分担擦写任务,避免个别块过早损坏,从而最大化整个设备的寿命。
7.2 动态与静态磨损均衡
- 动态磨损均衡:
当有新数据写入时,FTL 会从空闲块池中选择擦除次数最少(最年轻)的块来使用。但这只能保证新数据均匀分布,那些存放“冷数据”(长期不修改的数据)的块会因为一直不被触碰而“偷懒”。 - 静态磨损均衡(高级策略):
为了解决冷数据问题,FTL会定期扫描。如果发现某些块长期存放冷数据且磨损很低,而其他块磨损很高,FTL会强制将冷数据搬运到那些磨损高的块中去。
虽然这会产生额外的写放大(为了搬运冷数据),但它让那些原本“闲置”的低磨损块也参与到了写入循环中,极大地延长了设备的整体寿命。
7.3 总结
垃圾回收、写放大和磨损均衡是 Flash 管理中的“铁三角”:
- 异地更新解决了写入难的问题,但产生了垃圾。
- 垃圾回收清理了垃圾,但导致了写放大。
- 磨损均衡为了保护寿命,通过数据搬家进一步增加了写放大,但换取了设备的长久稳定。
优秀的 FTL 算法(无论是硬件 SSD 还是软件 YAFFS),核心目标就是在保证性能的前提下,通过精妙的算法平衡这三者,让 Flash 设备既快又耐用。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)