3. 文件系统与分区

在 Android IO 性能调优中,文件系统与分区布局是绕不开的底层基础。同一个 eMMC/UFS 设备,换用不同文件系统、不同挂载参数,随机写性能可能相差数倍;同一份系统镜像,采用只读压缩文件系统后,既节省空间又提升读取速度。理解 ext4、F2FS、EROFS、FAT32 的定位差异,以及 Android 分区布局与挂载参数的含义,是后续分析 IO 瓶颈、定位卡顿与优化启动速度的前提。

一、核心原理:四类文件系统的定位差异

Android 设备上常见的文件系统并非随意选择,而是根据分区用途、读写特征和存储介质特性来匹配的。

  • ext4:传统 Linux 日志文件系统,成熟稳定,支持日志、延迟分配、extent、多块分配等特性。它适合通用读写场景,但在闪存设备上存在日志写入放大、随机写放大等问题,长期使用后碎片化会影响性能。
  • F2FS:Flash-Friendly File System,由三星主导设计,专门面向 NAND 闪存。它采用日志结构式写入、冷热数据分离、多级检查点等机制,能显著降低随机写放大,提升闪存寿命与随机写性能,是 Android 用户数据分区的主流选择。
  • EROFS:Enhanced Read-Only File System,只读压缩文件系统。它支持固定大小输出压缩、按需解压,读取时无需整块解压,随机读性能好、镜像体积小,适合 system、vendor、product 等只读系统分区。
  • FAT32:兼容性极佳的简单文件系统,广泛用于外置 SD 卡、U 盘等可移动存储。它不支持日志、权限模型简单、单文件最大 4GB,性能与可靠性较弱,通常只用于外部存储。

从读写属性看,系统分区多为只读,用户数据分区为读写,外置存储为可插拔读写。选择文件系统时,应优先匹配“读多写少”“写多读少”“随机写密集”等真实 IO 模式。

二、Android 分区布局与挂载参数

Android 采用分区化设计,每个分区承担明确职责。典型布局包括:boot、init_boot、dtbo、vbmeta、super(动态分区,内含 system、vendor、product、system_ext 等)、userdata、metadata、cache、persist、misc 等。其中 super 分区通过动态分区机制管理多个只读逻辑分区,userdata 承载用户数据与 App 私有目录,是随机写最集中的区域。

挂载参数直接决定 IO 行为。常见参数包括:

# 典型 userdata 挂载(F2FS)
/dev/block/by-name/userdata /data f2fs rw,seclabel,nosuid,nodev,noatime,nodiratime,
background_gc=on,discard,inline_xattr,inline_data,inline_dentry,flush_merge,
extent_cache,mode=adaptive,active_logs=6,reserved_blocks=5,checkpoint=disable

# 典型 system 挂载(EROFS)
/dev/block/by-name/system /system erofs ro,seclabel,relatime,context=u:object_r:system_file:s0

# 典型外置存储(FAT32)
/dev/block/mmcblk1p1 /mnt/media_rw/XXXX vfat rw,nosuid,nodev,noexec,relatime,
uid=1023,gid=1023,fmask=0007,dmask=0007,allow_utime=0020

其中 noatime 避免读操作触发元数据写;discard 或 background_gc 影响闪存回收;inline_data 让小块数据直接存入 inode,减少额外块访问;flush_merge 合并刷写请求,降低随机写开销。EROFS 的 ro 与压缩特性则让系统分区读取更高效。

Android 分区布局与文件系统映射 只读系统分区 · 读写用户分区 · 可插拔外置存储 物理存储介质:UFS / eMMC(NAND Flash) 引导分区组 boot / init_boot dtbo / vbmeta 只读 · 启动校验 super 动态分区 system / vendor / product system_ext / odm EROFS 只读压缩 userdata / metadata /data · App 私有目录 数据库 / 缓存 / 媒体 F2FS 读写 · 随机写密集 外置可移动存储:SD 卡 / U 盘 FAT32 / exFAT · 兼容优先 · 无日志 · 单文件 4GB 限制 关键挂载参数与作用 noatime / nodiratime 避免读触发元数据写 inline_data / flush_merge 小数据内联 · 合并刷写 discard / background_gc 闪存回收与垃圾回收 ro / relatime 只读挂载 · 减少时间戳写

三、案例:一次启动慢与随机写卡顿的排查

某中端机型反馈“开机慢、应用安装慢、相册滑动卡”。抓取 /proc/mounts 与 iostat 后发现:userdata 使用 ext4 且未开启 noatime,随机写 IOPS 偏低;system 分区未启用 EROFS,镜像体积大、读取解压开销高。

# 查看当前挂载与文件系统
adb shell cat /proc/mounts | grep -E "data|system|vendor"
adb shell mount | grep f2fs

# 查看块设备 IO 统计
adb shell cat /proc/diskstats
adb shell iostat -x 1 5

# 查看 F2FS 状态
adb shell cat /sys/fs/f2fs/dm-0/segment_info

优化动作:将 userdata 迁移到 F2FS 并启用 inline_data、flush_merge、background_gc=on;system 改用 EROFS 并开启压缩;挂载参数统一加入 noatime。复测后随机写 IOPS 提升约 40%,开机时间缩短约 15%。

四、误区与复盘

误区一:所有分区都用 F2FS 最好。F2FS 面向随机写优化,但只读系统分区用 EROFS 更省空间、读取更快;引导分区数据量小,ext4 或专用格式即可,盲目统一反而增加复杂度。

误区二:挂载参数照抄即可。不同 UFS 版本、不同厂商固件对 discard、gc_urgent 的支持不同,照抄可能引发额外写放大或兼容问题,必须结合实测。

误区三:只看顺序读写。Android 真实负载以随机小 IO 为主,评估文件系统应重点看 4K 随机读写、数据库事务与元数据操作。

文件系统 典型分区 读写属性 核心优势 主要局限
ext4 boot、部分旧设备 userdata 读写 成熟稳定、工具链完善 闪存写放大、碎片化
F2FS userdata、metadata 读写 随机写性能好、寿命友好 实现复杂、参数敏感
EROFS system、vendor、product 只读 压缩省空间、随机读快 不可写、需构建支持
FAT32 外置 SD 卡、U 盘 读写 兼容性极强 无日志、4GB 限制、性能弱

调优顺序建议:先确认分区用途与读写特征,再选文件系统,最后调挂载参数。任何参数变更都应通过 /proc/diskstats、iostat、systrace 做前后对比,避免凭感觉优化。