嵌入式NAND闪存文件系统选型:JFFS2、YAFFS2与UBIFS深度对比
1. 项目概述:为什么NAND闪存需要“特供”文件系统?
如果你在嵌入式或者移动设备领域摸爬滚打过几年,肯定对“存储介质选型”这个老生常谈的话题不陌生。从早期的NOR Flash存代码,到后来大容量的NAND Flash存数据,再到如今eMMC、UFS的普及,存储技术的发展总是围绕着容量、速度和成本在打转。但有一个核心问题始终没变:硬件变了,管理硬件的软件——文件系统,也得跟着变,否则就是“小马拉大车”或者“大炮打蚊子”。
NAND闪存就是个典型例子。它价格便宜、容量大,迅速取代了硬盘成为嵌入式设备和移动电脑的主要存储。但它的脾气很怪:不能像硬盘那样直接覆盖写数据(必须先擦除再写入),读写的基本单位(页)和擦除的基本单位(块)大小不同,而且每个块都有擦写寿命。如果你把为硬盘设计的EXT4或者FAT32文件系统直接怼到NAND闪存上,用不了多久,不是数据错乱,就是闪存被“写死”——某些频繁擦写的块提前报废。
这就催生了一个专门的技术领域:NAND闪存专用文件系统。它们不是简单的“适配层”,而是从底层架构上就为闪存的特性量身定做。今天我们要深入聊的,就是Linux生态里三位鼎鼎大名的“特供专家”:JFFS2、YAFFS2和UBIFS。我经历过从JFFS2迁移到UBIFS的完整过程,也调试过YAFFS2在各种奇葩NAND芯片上的兼容性问题。这篇文章,我会结合这些一线实战经验,不仅告诉你它们的技术原理和性能数据,更会分享在真实项目中如何根据你的板子、你的需求来做选择,以及那些手册里不会写的“坑”和技巧。
简单来说,选对文件系统,你的设备启动能快好几秒,内存能省下好几兆,寿命能延长好几年。选错了,可能就是无尽的掉数据、启动慢和性能瓶颈的噩梦开始。
2. 核心原理:闪存文件系统是如何“驯服”NAND的?
在直接对比三位选手之前,我们必须先统一“比赛规则”,理解它们共同要解决的挑战。你可以把NAND闪存想象成一个巨大的、结构特殊的笔记本。
2.1 NAND闪存的硬件“怪癖”
这个“笔记本”有以下几个关键特性,直接决定了文件系统的设计思路:
- 基本操作单元特殊:读写的最小单位是“页”(Page,通常2KB、4KB、8KB甚至16KB),而擦除的最小单位是“块”(Block,通常由64、128或256个页组成)。这意味着,哪怕你只想改一个字节,理论上也得把整个块(可能128KB)读出来,在内存里改好,再把整个块擦掉,最后把新数据写回去。显然,不能这么蛮干。
- 异地更新(Out-of-place Update):由于“先擦后写”的限制,直接在原位置更新数据(In-place Update,像硬盘那样)效率极低。因此,所有闪存文件系统的核心思想都是异地更新。新数据直接写到空闲页上,旧数据所在页被标记为“无效”。这个设计带来了一个副产品:垃圾。
- 垃圾回收(Garbage Collection):随着不断写入,无效数据会越来越多,占据大量空间。文件系统需要定期进行“大扫除”,把同一个块里还“有效”的数据搬到一个新的空闲块,然后把旧块整个擦除,回收空间。这个过程就是垃圾回收,它会带来额外的写入(写有效数据)和擦除操作,直接影响性能和寿命。
- 寿命有限(有限的擦写次数):每个闪存块都有擦写次数上限(P/E Cycle,通常是几千到几万次)。如果某个块频繁被擦写,它会率先“累死”,变成坏块。因此,文件系统必须实现磨损均衡(Wear Leveling),通过算法让擦写操作尽可能均匀地分布到所有块上,避免“旱的旱死,涝的涝死”。
- 存在坏块(Bad Block):NAND闪存在出厂时或使用过程中都可能产生坏块。文件系统必须能识别并绕过这些坏块,对上层应用透明。
2.2 闪存文件系统的通用架构
为了应对上述挑战,一个典型的闪存专用文件系统通常采用如图所示的逻辑架构。文件数据本身存储在闪存介质上,而所有的运行时信息(如文件管理结构、元数据索引、缓存的文件数据)都保存在内存中。当文件系统挂载(mount)时,它需要扫描闪存上的数据,在内存中重建出完整的目录树和文件索引结构。这个“重建”过程的速度,直接决定了系统的启动时间。
其核心功能模块可以概括为三点:
- 闪存布局(Flash Layout):决定如何将元数据(如超级块、inode)和文件数据排布在物理闪存上。主流方案是采用日志结构(Log-structured),所有写操作(包括元数据更新)都像写日志一样追加到末尾,天然适合异地更新。
- 内存数据组织(In-memory Data Organization):设计高效的内存数据结构来管理元数据和缓存,这直接影响文件访问速度和内存占用。
- 闪存管理(Flash Management):负责地址映射(把文件逻辑偏移转换成物理页地址)、坏块管理和触发垃圾回收。在一些设计中,这部分功能由一个独立的“闪存转换层”(FTL)实现,但对嵌入式Linux来说,更常见的做法是由文件系统自身直接管理物理闪存,这就是JFFS2/YAFFS2的做法;或者通过一个像UBI这样的中间层来管理,再由其上的文件系统(如UBIFS)使用。
理解了这些共同的基础,我们就能更清晰地看到JFFS2、YAFFS2和UBIFS在实现路径上的分岔路口了。
3. 三位选手的技术解剖:JFFS2、YAFFS2与UBIFS
Linux内核为存储设备管理提供了丰富的子系统。对于硬盘这类块设备,有通用的块设备层。但对于闪存,Linux提供了更底层的MTD(Memory Technology Device)子系统。MTD抽象了闪存芯片的读、写、擦除接口,并知晓坏块的存在。JFFS2和YAFFS2都是直接工作在MTD设备之上的。
后来,为了提供更强大的功能(如全设备范围的磨损均衡、动态卷管理),又诞生了UBI(Unsorted Block Images)层。UBI在MTD之上,提供了“逻辑擦除块”的概念,并负责逻辑块到物理块的映射、坏块管理和磨损均衡。UBIFS,顾名思义,就是工作在UBI卷之上的文件系统。
这个架构选择,是理解三者差异的第一把钥匙。
3.1 JFFS2:日志结构的开拓者
JFFS2最初是为NOR闪存设计的,后来才加入对NAND的支持。它是一个纯粹的日志结构文件系统。
核心设计:
- 基本单元是“节点”(Node):每个节点包含可变长度的数据或元数据,并附属于一个特定的文件(inode)。每个节点都记录了物理地址、长度,并通过链表指向同一个文件的下一个节点。每次写操作都会生成一个新节点。
- 挂载慢:由于没有在闪存上存储集中的索引,JFFS2挂载时必须扫描整个MTD分区的所有节点,在内存中重建出完整的文件目录树。分区越大、文件越多,挂载时间就越长。这是JFFS2最被诟病的一点。
- 垃圾回收与磨损均衡:JFFS2在内存中维护了几个链表来管理擦除块的状态(干净块、脏块、空闲块)。垃圾回收时,它采用一种简单的概率算法(基于jiffies计数器)来选择回收脏块还是干净块,以此实现基本的磨损均衡。
- 优化手段:
- 摘要(Summary):为了加速挂载,JFFS2支持在擦除块末尾(EBS)或文件系统卸载时(CS)存储摘要信息。下次挂载时可以直接读取摘要,避免全盘扫描。但这需要正常卸载(clean unmount)才能生效。
- 压缩:支持zlib、lzo等压缩算法,可以有效提高存储空间利用率,尤其适合存储大量文本、代码等可压缩数据。
实操心得:在早期NAND容量不大(几百MB以内)、系统内存紧张的项目中,JFFS2是可靠的选择。但务必开启
summary支持,并确保系统正常关机,否则下次启动的扫描时间会让你抓狂。对于只读的文件系统分区(如rootfs),JFFS2的压缩特性非常有用。
3.2 YAFFS2:为NAND而生的直管方案
YAFFS是第一个专门为NAND闪存设计的文件系统。它直接工作在MTD层上,深度利用了NAND硬件的特性。
核心设计:
- 面向页(Page-Oriented):YAFFS2的基本管理单位是NAND的页。每个页在写入时,会在其备用区(Spare Area/OOB)记录关键元数据:文件ID(即inode号)和块号(Chunk Number)。文件数据按页大小被分割成一个个“块”。
- 挂载机制:挂载时,YAFFS2只需读取每个页的备用区,就能快速构建出内存中的文件结构。这听起来比JFFS2扫描全部数据区要快。但这里有个坑:很多硬件控制器不支持单独读取OOB区,导致YAFFS2实际上还是读了整个页,I/O优势大打折扣。当文件系统很大时,其内存消耗也会随文件数量线性增长。
- 贪婪垃圾回收:YAFFS2的垃圾回收算法比较“聪明”。当空闲块很多时,它很“懒”,只挑最脏(有效数据最少)的块来回收,减少开销。当空闲块紧张时,它才变得“勤奋”,回收有效数据更多的块以快速释放空间。这种策略旨在平衡性能和磨损。
- 检查点(Checkpoint):类似JFFS2的摘要,YAFFS2可以将内存中的状态保存到闪存,加速下次挂载。
注意事项:YAFFS2最大的优势是代码相对简单,且针对NAND特性优化。但其社区活跃度已不如当年,且未并入主流Linux内核树,需要打补丁。它的性能严重依赖于NAND控制器的能力。我曾在一个项目中使用YAFFS2,因为主控的OOB读取效率低下,导致挂载速度甚至比JFFS2还慢,不得不切换方案。
3.3 UBIFS:基于UBI的现代派
UBIFS可以看作是JFFS2的“精神续作”,但它构建在更强大的UBI层之上,因此架构更为复杂和现代。
核心设计:
- 基于UBI卷:UBI层解决了全设备磨损均衡和动态卷管理,让UBIFS可以专注于文件系统本身。UBIFS看到的是由UBI映射好的、没有坏块的“逻辑擦除块”(LEB)。
- 索引存储在闪存上:这是与JFFS2最大的不同。JFFS2的索引只在内存中,而UBIFS将主要的文件系统索引(一种“漫游树”Wandering Tree结构)也存储在了闪存上。这带来了一个巨大优势:挂载速度与闪存容量/文件数量成对数关系,而非线性关系。挂载时只需读取固定的超级块、主节点等区域,速度极快。
- 写回(Write-back)缓存:UBIFS在内存中维护了树节点缓存,支持延迟写入。数据先写入缓存,随后再批量提交到闪存的日志区域。这大大提升了写入性能,尤其是对于大量小文件操作。
- 复杂的片上布局:一个UBIFS分区被逻辑划分为多个固定区域(超级块、主节点、日志、LPT、孤儿区、主区域)。这种设计带来了良好的可扩展性,但也意味着有一定的空间开销(用于存储索引和元数据),在小容量闪存上可能不划算。
- 压缩:同样支持LZO/zlib压缩,但仅对文件数据有效,对元数据无效。
核心优势解析:UBIFS的快,主要快在两点:一是挂载时无需全盘扫描,二是写回缓存减少了实际写闪存的次数。但它的“重”也体现在两方面:代码体积比JFFS2/YAFFS2大,且需要UBI层,这增加了存储空间的固定开销(UBI需要预留一部分空间用于映射和坏块替换)。对于大容量(GB级别)eMMC或NAND,UBIFS几乎是当前Linux下的不二之选。
为了更直观地对比三者的核心特性和适用场景,我整理了下表:
| 特性维度 | JFFS2 | YAFFS2 | UBIFS |
|---|---|---|---|
| 内核支持 | 主线内核 | 需打补丁 | 主线内核 |
| 底层依赖 | MTD | MTD | UBI (再到底层MTD) |
| 核心结构 | 日志节点 | 页 + OOB元数据 | 索引树 (存储在闪存) |
| 挂载速度 | 慢 (线性扫描) | 中等 (依赖硬件) | 极快(读取固定区域) |
| 内存占用 | 中等,随文件数增长 | 中等,随文件数增长 | 较低且稳定,与容量对数相关 |
| 写入性能 | 一般 | 一般 | 优秀(写回缓存) |
| 空间开销 | 低 | 低 | 较高(UBI+索引占用固定空间) |
| 磨损均衡 | 基础 (概率算法) | 较好 (贪婪GC) | 优秀(由UBI层负责) |
| 压缩支持 | 是 (全数据) | 否 | 是 (仅文件数据) |
| 适用场景 | 小容量NAND,只读或低写,内存受限 | 专为NAND设计,中等容量,对内核版本有要求 | 大容量NAND/eMMC,对启动速度和性能要求高 |
4. 性能实测:数据背后的真相与选择逻辑
纸上谈兵终觉浅。我们来看一组基于真实硬件(PKUnity-SK SoC平台,2GB NAND)的实测数据,这能让我们更直观地感受差异。测试使用了Postmark基准,模拟了创建、删除、读取、追加文件等多种操作。
4.1 挂载时间:启动速度的生死线
挂载时间直接影响设备启动速度,是嵌入式产品用户体验的关键。
| 测试场景 | JFFS2 | YAFFS2 | UBIFS |
|---|---|---|---|
| 完整根文件系统 (128MB) | 37.5秒 | 52.0秒 | 0.22秒 |
| 子集文件系统 (3.8MB) | 7.8秒 | 3.4秒 | 0.21秒 |
结果分析:
- UBIFS一骑绝尘:无论文件系统内容多少,UBIFS的挂载时间都在毫秒级,几乎可以忽略不计。这得益于其将索引存储在闪存固定位置的设计。
- JFFS2与YAFFS2的拉锯:两者挂载时间都随容量/文件数线性增长。在大容量场景下,YAFFS2反而更慢(52秒 vs 37.5秒),这是因为其依赖OOB读取,而硬件可能不支持高效单独读取,导致实际I/O量更大。在小容量场景下,YAFFS2的简单数据结构使其略胜一筹。
- 压缩与检查点的影响:
- 为JFFS2/YAFFS2启用检查点(Summary/Checkpoint)后,挂载时间可大幅缩短(例如JFFS2从37.5秒降至6.4秒)。但这要求系统上次是正常关机。意外掉电会导致检查点失效,下次启动仍需全盘扫描。
- 启用压缩(如zlib)会略微增加CPU开销,可能影响挂载时间,但能节省空间。
选型指南:如果你的产品对启动速度有严苛要求(如消费电子、物联网设备),UBIFS是首选。如果启动速度要求不极端,且闪存容量较小(<256MB),JFFS2和YAFFS2可以权衡。务必记住:启用检查点并保证正常关机流程,是使用JFFS2/YAFFS2的生产环境必备条件。
4.2 内存消耗:资源受限系统的命门
嵌入式系统内存往往捉襟见肘,文件系统运行时占用的内存至关重要。
| 文件系统类型 | 代码大小 (KB) | 内存占用 - 完整系统 (KB) | 内存占用 - 子集系统 (KB) |
|---|---|---|---|
| JFFS2 | ~100 | 1012 | 80-228 |
| YAFFS2 | ~96 | 1640 | 64 |
| UBIFS | ~155 | 512 | 512 |
结果分析:
- UBIFS内存占用稳定:无论文件多少,UBIFS的内存占用基本恒定(约512KB)。这是因为其核心数据结构(树)的大小与容量成对数关系,且UBI层管理了大部分映射关系。
- JFFS2/YAFFS2随文件数增长:两者内存占用都随文件数量增加而显著上升。在文件极多时(测试中6435个文件),YAFFS2的内存占用(1640KB)甚至超过了JFFS2(1012KB),说明其数据结构在规模增大时扩展性不佳。
- 代码体积:UBIFS由于功能复杂(包含UBI),代码体积最大。JFFS2和YAFFS2相对轻量。
选型指南:在内存极度紧张(如只有几十MB RAM)的系统中,需要仔细评估文件数量。如果文件数很少(<1000),JFFS2和YAFFS2可能占优。如果文件数多或预期会增长,UBIFS恒定的内存占用是巨大优势,避免了因文件增多导致系统内存不足的风险。
4.3 读写性能与系统开销
我们使用Postmark测试了文件系统的综合事务处理能力。
| 指标 | JFFS2 | YAFFS2 | UBIFS |
|---|---|---|---|
| 完成时间 (秒) | 590 | 552 | 177 |
| 事务率 (#/秒) | 86 | 93 | 292 |
| 读取吞吐 (KB/s) | 410 | 438 | 1340 |
| 写入吞吐 (KB/s) | 428 | 458 | 1390 |
结果分析:
- UBIFS全面领先:其写回缓存机制极大地提升了小文件操作的性能。数据在内存中合并、延迟写入,减少了实际对闪存的擦写次数。
- YAFFS2略优于JFFS2:在纯NAND操作上,YAFFS2的针对性优化使其性能稍好。
- 压缩的代价:测试也显示,压缩率更高的算法(如zlib vs lzo)通常会带来性能下降,因为压缩/解压缩消耗了CPU时间。这是一个典型的空间换时间的权衡。
垃圾回收与磨损均衡成本: 通过追踪底层编程和擦除操作次数,可以评估文件系统对闪存寿命的影响。
| 测试 (运行1次Postmark) | JFFS2 | YAFFS2 | UBIFS |
|---|---|---|---|
| 写入次数 (千次) | 230 | 297 | 13 |
| 擦除次数 (千次) | 6 | 4 | 3 |
| 总成本 (写入+擦除) | 236 | 301 | 16 |
结果分析:
- UBIFS成本最低:得益于写回缓存,许多临时文件的创建/删除操作在内存中就被合并或抵消了,无需真正写回闪存,极大地减少了实际I/O。
- YAFFS2写入次数最多:因为其元数据(如文件创建、删除)也需要占用整页写入,在Postmark这种元数据密集型的测试中显得效率不高。
- 磨损均衡:三者的磨损均衡都做得不错,擦除次数的标准差很小。UBIFS由于擦除总数少,且由UBI层负责全局均衡,在延长闪存寿命方面具有天然优势。
5. 终极选型指南与实战避坑
看完理论和数据,到底该怎么选?这没有银弹,只有最适合你场景的方案。我根据多年项目经验,总结出以下决策路径和实战要点。
5.1 根据应用场景选择
场景一:追求极致启动速度的消费电子产品(如智能音箱、路由器)
- 首选:UBIFS。毫秒级挂载带来的快速开机体验是核心竞争力。大容量eMMC也是UBIFS的主场。
- 注意:需确认主控芯片的UBI驱动稳定,且为UBI/UBIFS预留足够的预留空间(通常几个百分比)。
场景二:小容量、低成本、内存紧张的工业控制设备(如MCU+小容量SPI NAND)
- 候选:JFFS2。代码精简,空间利用率高(尤其开启压缩后),在几十到几百MB的NAND上表现尚可。
- 必须做:务必开启
summary支持,并在产品设计中保证正常关机流程(如超级电容、软件关机信号)。同时,要评估最大文件数量,避免内存占用超标。 - 替代方案:如果NAND质量一般或担心坏块,可以考虑
squashfs(只读) +overlayfs(可写)的方案,将只读根文件系统压缩为squashfs,写操作由基于JFFS2或tmpfs的overlay层承担。
场景三:专为NAND优化、且内核版本较老或定制的项目
- 候选:YAFFS2。如果团队对YAFFS2有历史积累,且使用的NAND控制器能高效处理OOB,它仍然是一个直接有效的选择。
- 警惕:社区支持减弱,未来可能遇到新内核适配问题。务必进行充分的压力测试,特别是异常掉电测试。
5.2 关键配置与调优要点
无论选择哪个,正确的配置都至关重要。
对于JFFS2:
- 挂载选项:使用
-o summary挂载以启用摘要。如果分区是只读的,可以加-o ro避免扫描。 - 压缩选择:在
make menuconfig中可以选择默认压缩算法。lzo压缩速度快,占用CPU少;zlib压缩率高,节省空间。根据你的数据类型和CPU性能选择。 - 预留空间:确保闪存分区不要塞得太满(建议至少预留5%-10%),为垃圾回收提供操作空间,否则性能会急剧下降。
对于UBIFS:
- UBI格式化:在创建UBIFS镜像前,需要先用
ubinize工具处理。关键参数是-m(最小I/O单位,即页大小)、-p(物理擦除块大小)、-s(子页大小,通常与页大小一致或为0)。# 示例:从目录制作用于256KB擦除块、2KB页的NAND的UBI镜像 mkfs.ubifs -r rootfs -m 2048 -e 253952 -c 1000 -o ubifs.img ubinize -o ubi.img -m 2048 -p 256KiB -s 2048 ubinize.cfgubinize.cfg中需要指定vol_size(逻辑卷大小)和vol_type(动态/静态)。 - LEB大小计算:
LEB Size = PEB Size - (2 * Page Size)。这是因为UBI需要在每个物理擦除块的开头和结尾存放卷标识符等元数据。例如,对于128KB块、2KB页的NAND,LEB = 131072 - (2*2048) = 126976 bytes。这个计算错误是导致UBIFS挂载失败的最常见原因之一。 - 空间开销:理解UBI/UBIFS有自己的元数据开销(用于存储索引、日志等)。在规划分区大小时,这部分空间(可能占总体容量的1-2%)需要被考虑进去。
通用建议:
- 进行掉电测试:在任何文件系统投入生产前,必须进行严格的随机掉电测试。观察文件系统是否能够恢复,数据一致性如何。JFFS2和YAFFS2在没有检查点的情况下,掉电后首次挂载扫描时间会很长。
- 监控磨损:对于UBIFS,可以通过
ubiattach后查看/sys/class/ubi/ubiX/下的wear_leveling等节点来监控磨损情况。对于MTD直管的文件系统,监控手段较少,更依赖算法本身的可靠性。
5.3 常见问题排查实录
问题1:JFFS2挂载时间过长,甚至超时。
- 排查:首先检查内核日志
dmesg,看是否在扫描。使用mount -t jffs2 -o summary /dev/mtdblockX /mnt挂载。如果上次是非正常关机,摘要无效,扫描无法避免。根本解决方法是优化关机流程,或考虑切换到UBIFS。 - 临时缓解:如果分区内容基本不变,可以考虑在开发阶段扫描一次后,将生成的
summary节点固化到镜像中,但这不是标准做法。
问题2:UBIFS挂载失败,报错“Invalid argument”或“Cannot mount mtdX”。
- 排查:99%的问题出在LEB大小计算错误或ubinize配置错误。double-check你的NAND芯片手册,确认
Page Size和Block Size。重新计算LEB大小,并确保mkfs.ubifs和ubinize命令中的-e(逻辑擦除块大小)参数一致且计算正确。 - 检查步骤:
- 确认内核配置已启用
CONFIG_MTD_UBI和CONFIG_UBIFS_FS。 - 使用
flash_erase擦除MTD分区。 - 使用
ubiformat格式化MTD分区为UBI设备(这会处理坏块)。 - 使用
ubiattach关联MTD分区。 - 使用
ubimkvol创建卷。 - 最后使用
mount -t ubifs挂载。按步骤操作并观察每一步的输出。
- 确认内核配置已启用
问题3:文件系统在使用一段时间后,剩余空间充足但写入报“No space left on device”。
- 原因:这是垃圾回收跟不上写入速度的典型表现。虽然逻辑上有空间,但物理上缺少已经擦除的、可直接写入的空闲块。垃圾回收线程正在努力擦出新的空闲块,但速度赶不上你的写入请求。
- 解决:
- 增加预留空间:这是最有效的方法。给文件系统分区更大的预留空间(比如从5%增加到15%),给垃圾回收更充裕的操作空间。
- 优化写入模式:避免突发性的、持续的大量小文件写入。如果业务允许,尝试将写入操作批量化和顺序化。
- 监控:在系统运行期间,监控
/proc/mtd(对于MTD)或UBI sysfs接口,观察擦除块状态。
问题4:YAFFS2在特定平台性能远低于预期。
- 排查:重点检查NAND控制器驱动。YAFFS2性能严重依赖OOB操作的效率。有些控制器驱动在读取OOB时,会强制连带整个数据页一起读取,这就完全丧失了YAFFS2的设计优势。可以尝试在YAFFS2配置中关闭OOB缓存等优化选项,或者直接对比JFFS2的性能。如果驱动层无法优化,换用JFFS2或UBIFS可能是更实际的选择。
经过这么多年的演进,在Linux嵌入式领域,UBIFS已经成为大容量NAND和eMMC存储的事实标准,其快速的挂载、稳定的内存占用和优秀的写入性能,使其在大多数现代项目中都是更省心、更面向未来的选择。JFFS2在小容量、低成本领域仍有其价值,但需要精心设计和测试。YAFFS2则更像一个特定历史时期和硬件条件下的优化方案,在新项目中已较少被作为首选。
最终的选择,一定要回归到你的具体需求:容量多大?内存多少?启动时间要求多严?写入模式是怎样的?预算和硬件是否固定?结合这些约束,再对照上面三个文件系统的特性,你就能找到那条最合适的路径。记住,没有最好的,只有最合适的。
