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 与压缩特性则让系统分区读取更高效。
三、案例:一次启动慢与随机写卡顿的排查
某中端机型反馈“开机慢、应用安装慢、相册滑动卡”。抓取 /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 做前后对比,避免凭感觉优化。