垃圾回收

静态与动态索引

基本包使用静态索引。当 pkgfs 启动时,基于位于 /system/data/static_packages 中的 static_packages 索引,基本包会被预填充到 /pkgfs/packages 当中。这些静态包之后会被用来启动系统,诸如 pkg_resolver, pkg_cache, netstack, sysmgr 之类的核心组件将会被启动。

重启之后 pkgfs 会被重置,但是基本包会始终存在(基本包不能被删除)。

动态索引会保存一个所有临时获取的包的映射。pkgfs 会使用 /system/data/cache_packages 中存在的所有包(例如 meta.farBLOB 相关的)来预填充动态索引。通过使用包的 $name/$variant 作为键,动态索引能始终指向一个同名包的最新版本。pkgfs 会忽略该包较旧的版本。旧版本的包在系统中仍然存在,但是无法被引用。因此,动态索引能够用来实现垃圾回收机制。

如何实现垃圾回收

在 Fuchsia 中没有安装一个包或删除一个包的概念。准确地说,垃圾回收可以被当作是回收空间的一种手段。垃圾回收可以通过 pkgctl gc 来手动触发,也可以被 system-updater 触发。垃圾回收的实现可参考 fuchsia.space/Manager protocol。通过 system-updater 会在两种情况下触发垃圾回收,一是系统升级之前,二是在获取到 更新包之后。

pkgfs 的垃圾回收机制目前通过排除法来决定哪个包才是有效的包。满足以下任一条件,则该包为有效包:

  • 该包为静态索引中的基本包
  • 该包正在升级中(通过追踪 meta.far 和任意的缺失的 BLOB 的墨克根(merkle root),直到它们被完全解析)
  • 该包是某个临时包的最新版本(根据其在动态索引中的 meta or package 来判断)

运行垃圾回收时,它会删除未被有效包引用的 blobfs 中的所有 BLOB

已知问题

目前的垃圾回收机制并非最优,仍存在如下缺陷。

  • 正在使用的旧版本包也会被回收。这会导致某个组件下的包被当作垃圾清除掉。
  • 如果 system-updater 没能成功下载新的包,垃圾回收器会同时保留新包和旧版本的包,这导致每个包都有重复的副本。如果发生这样的情况,需要重启设备来清除被激活的包的列表。