SharedPreferences 存储大量数据时会出现什么性能问题?如何优化?
解读
面试官想确认两点:
- 候选人是否真正踩过“SP 存大对象”的坑,而不仅仅背“轻量级存储”概念;
- 能否给出国内真实业务场景下的量化数据与工程化解决方案,而不是泛泛而谈“用 MMKV/数据库”。
回答时要围绕“一次 commit/apply 到底做了什么”展开,把主线程阻塞、GC、anr、电量、系统锁竞争讲透,再给出国内主流 App(日活千万级)验证过的优化路径。
知识点
- 实现机制:SP 本质是
/data/data/<pkg>/shared_prefs/*.xml的 DOM 树,全部驻内存(SharedPreferencesImpl.mMap),每次 commit/apply 全量序列化到磁盘,文件大小与内存占用 1:1。 - 事务模型:commit 同步阻塞调用方,apply 异步但仍把全量 xml 写入队列,队列由单线程
QueuedWork.singleThreadExecutor串行执行,阻塞后续 apply 与组件生命周期(Activity stop/Service stop)的QueuedWork.waitToFinish()。 - 性能拐点:国内低端机实测,xml 超过 100 KB 时第一次读入耗时 15-20 ms;超过 300 KB 时单次 apply 落盘 80-120 ms,连续 5 次触发“等待”逻辑即可造成 Input ANR(主线程 5 s 无响应)。
- 稳定性:xml 采用
FileUtils.writeFileAtomically(),先写.bak再重命名,大文件场景下 fsync 耗时翻倍,极端情况下触发系统 WatchDog。 - 国内加固与渠道:部分加固框架会 hook
SharedPreferencesImpl.writeToFile(),导致全量写放大 1.3-1.5 倍;华为/小米后台省电策略对 fsync 限频,进一步放大卡顿。 - 官方替代:Jetpack DataStore 基于 Kotlin Coroutines 与 Protobuf,增量写入,无 xml,但 API 仍在 1.0.x,国内大型 App 落地节奏慢;MMKV 基于 mmap,增量更新,微信 10 亿级验证,已写入腾讯开源镜像站,国内接入成本最低。
答案
“SharedPreferences 设计初衷是存少量标志位,当 value 累计到几十 KB 以上就会出现三类性能问题:
- 主线程阻塞:commit 直接阻塞调用线程;apply 虽异步,但 Activity 生命周期会等待
QueuedWork完成,xml 越大等待越久,低端机 300 KB 就能触发 ANR。 - 内存与 GC:整个 xml 被加载到
ConcurrentHashMap,再序列化StringBuilder到字节数组,大对象直接进入 Old 区,频繁编辑造成 GC 抖动。 - 电量与锁竞争:每次全量写盘伴随
fsync,文件越大耗时越久,后台监控显示连续写入 500 KB 可使 CPU 使用率瞬间升高 15%,在小米/华为限频机型上容易被系统标记为异常耗电。
国内一线 App 的优化套路分三步:
第一步,量化:在灰度环境埋点,统计所有 xml 文件大小及 apply 耗时,把 >100 KB 的文件列为“红色阈值”。
第二步,拆分与降级:
- 把缓存型大数据(如 JSON、路由表、埋点采样配置)迁移到 MMKV,读写耗时降低 90%,内存占用减少 70%;
- 把结构化业务数据(用户足迹、商品快照)迁移到 Room,利用 SQLite 的页缓存与 WAL 增量日志;
- 仅保留真正的“标志位”在 SP,如首次启动、隐私协议弹窗状态,单文件控制在 20 KB 以内。
第三步,写入策略: - 批量聚合后一次性 apply,避免循环写;
- 对即时性要求不高的 key,使用
LifecycleCoroutineScope在进程空闲时延迟写入,减少与主线程生命周期冲突; - 在应用启动时预加载常用 SP 到内存缓存,后续只读不写,彻底消除运行时 IO。
通过以上手段,我们现网将 SP 平均文件大小从 260 KB 降到 8 KB,ANR 率下降 38%,后台耗电评分提升 0.12 分(华为应用市场评分),验证了方案在国内主流机型上的有效性。”
拓展思考
- 如果团队已全面 Kotlin 协程化,可继续追问“DataStore 与 MMKV 在一致性、跨进程、备份恢复上的差异”,考察是否读过源码。
- 车载或 Wear 场景下闪存寿命敏感,需进一步追问“mmap 频繁增量写入是否会带来 flash 写放大,如何权衡缓存与寿命”。
- 国内厂商后台清理策略各异,可延伸讨论“如何将 SP 迁移到云端配置 + 本地 LRU 缓存”实现可灰度、可回滚的用户体验。