RFC-0280:VMO 参考和切片属性

RFC-0280:VMO 引用和切片归因
状态已接受
区域
  • Kernel
说明

建议更改 VMO 的引用和切片子项的内存归因。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2026-03-31
审核日期(年-月-日)2026-03-31

问题陈述

引用和切片是 VMO 子项类型,可将读取和写入等操作转发到父 VMO。操作的行为就像是在父 VMO 的重复句柄上执行一样。

目前,当使用 zx_object_get_info 查询时,引用和切片会针对所有字段报告零个归因字节 。

此外,无法查询 VMO 是引用还是切片,因此很难判断零个归因字节是否意味着没有内容。API 用户依赖于黑客攻击来检测和归因这些克隆类型。

此方案导致了一些问题。

Fxfs

Fxfs 使用引用来向 blob 和可变文件提供句柄。这存在问题,因为在使用现有 API 时,无法检索文件保持打开状态的客户端的相关信息。为了归因于 fxfs,内存监控器目前依赖于一种黑客攻击,该黑客攻击将总字节数为 0 的所有 VMO 视为引用。

IOBuffers

IOBuffers 使用引用来跟踪端点上的对等方。 在 IOBuffer 实现中,根 VMO 位于内核中,因此无法从用户空间查询归因。这种情况还包括嵌套引用,这进一步使情况复杂化。

孤立内存

如果 VMO 在仅具有引用和切片克隆时被丢弃,则原始 VMO 的 VmCowPages 将保持活动状态,但这些页面不会归因于任何 VMO。由于 API 限制,无法检索有关原始 VMO 或其克隆的任何信息,因此内存监控器会将此视为“孤立内存”。

摘要

此 RFC 建议通过 zx_object_get_info 更改 VMO 的引用和切片子项的内存归因。引用和切片子项现在将报告内存,就像查询是在父项上执行的一样。切片只会报告其可见范围内的字节。

此外,zx_info_vmo::flags 中将添加两个新标志,以便用户可以查询 VMO 是引用 (ZX_INFO_IS_REFERENCE) 还是切片 (ZX_INFO_VMO_IS_SLICE)。

这些更改应为 API 用户提供足够的信息,以便他们自行管理引用归因。

利益相关方

协调人

jamesr@google.com

审核人

etiennej@google.com、rashaeqbal@google.com

咨询对象

adanis@google.com

社交化

一份概述现有归因方案的问题、建议的解决方案以及考虑过的替代解决方案的文档已发送至 fuchsia-memory-wgzircon-discuss 邮件列表以征求意见。

要求

为了使内存监控器和一般内存记账功能正常运行(包括模拟 Linux 内存归因 API),仍应能够根据 zx_info_vmo_t 中提供的信息计算这些标准指标:

  • 总内存(相当于 RSS/常驻集大小)
    • “此 VMO 引用的总内存”
  • 专用内存(相当于 USS/唯一集大小)
    • “如果此 VMO 被销毁,将释放的内存”
  • 缩放内存(相当于 PSS/比例集大小)
    • “此 VMO 在总内存中所占的份额”
    • 必须与系统内存总用量相加

设计

zx_object_get_info返回的归因信息将发生更改 ,以便引用和切片报告字节,就像它们是父项一样。 zx_info_vmo::flags 中将添加两个标志,以便用户可以查询 VMO 是引用 (ZX_INFO_IS_REFERENCE) 还是切片 (ZX_INFO_VMO_IS_SLICE)。

这样,API 用户就可以决定如何为引用归因字节。总内存可以报告为引用是父项。新标志可用于为专用内存返回 0,并正确计算总内存。

引用示例

以下是引用归因更改的示例:假设有一个 VMO,其中包含两个已提交的页面和一个引用子项。假设页面大小为 4096,以下是 API 查询的更改方式。

现有归因:

zx_info_vmo_t info;
reference.get_info(ZX_INFO_VMO, &info, sizeof(info), nullptr, nullptr)

info.committed_bytes = 0
info.populated_bytes = 0
info.committed_private_bytes = 0
info.populated_private_bytes = 0
info.committed_scaled_bytes = 0
info.populated_scaled_bytes = 0
info.committed_fractional_scaled_bytes = 0
info.populated_fractional_scaled_bytes = 0

建议的归因:

zx_info_vmo_t info;
reference.get_info(ZX_INFO_VMO, &info, sizeof(info), nullptr, nullptr)

info.committed_bytes = 8192
info.populated_bytes = 8192
info.committed_private_bytes = 8192
info.populated_private_bytes = 8192
info.committed_scaled_bytes = 8192
info.populated_scaled_bytes = 8192
info.committed_fractional_scaled_bytes = 0
info.populated_fractional_scaled_bytes = 0

info.flags & ZX_INFO_IS_REFERENCE = true;
info.flags & ZX_INFO_IS_SLICE = false;

切片示例

如果我们有一个 VMO,其中包含两个已提交的页面和一个单页切片,假设页面大小为 4096,以下是新 API 将报告归因的方式。它的行为就像是在父项上查询切片可见范围的归因一样。

建议的归因:

zx_info_vmo_t info;
slice.get_info(ZX_INFO_VMO, &info, sizeof(info), nullptr, nullptr)

info.committed_bytes = 4096
info.populated_bytes = 4096
info.committed_private_bytes = 4096
info.populated_private_bytes = 4096
info.committed_scaled_bytes = 4096
info.populated_scaled_bytes = 4096
info.committed_fractional_scaled_bytes = 0
info.populated_fractional_scaled_bytes = 0

info.flags & ZX_INFO_IS_REFERENCE = false;
info.flags & ZX_INFO_IS_SLICE = true;

实现

此更改的内核实现将很简单,但需要与内存监控器协调,以确保它们不会报告来自引用和切片的错误值。

性能

此更改将引入对 cow-pages 树的遍历,否则我们将返回零,因此在查询某些引用时,zx_object_get_info 可能会变慢。

安全注意事项

通过查询“*_scaled”字段或将引用中的专用字节与非专用字节进行比较,可以推断出有关原始 VMO 的写入时复制克隆的边信道信息,这在旧归因方案中是不可能的。这不会给当前引用用户带来任何问题。

预计这不会在未来的使用中造成问题,因为拥有引用在概念上类似于拥有 VMO 的额外句柄。

隐私注意事项

不适用

测试

需要更新任何查询引用或切片归因的现有测试。

文档

zx_object_get_info 系统调用 的文档将更新。

缺点、替代方案和未知事项

此设计的一个缺点是,如果父 ID 用于确定拥有页面的 VMO,则可能会引入嵌套引用的重复计数 bug。

另一种方法是扩展共享,以包含引用和切片以及写入时复制子项。这将对系统进行更大的更改,因为它会更改写入时复制克隆的归因,并且需要为所有 VMO 修改 USS 和 PSS 的计算。