Sysmem VMO 管理

本文档介绍了 SysmemVMO 的层次结构, 用于管理内存的方法本文档假定您熟悉虚拟 内存非系统内存的计算 在 Fuchsia 上。

所有 VMO 都是从堆分配的。当前的堆为:

名称 固定泳池 说明
系统核心 通用主内存
SysmemAmlogicProtectedPool 无法从 CPU 访问内存
SysmemContiguousPool 物理连续的主内存
tee_secure 适用于 Amlogic 解密编码视频的特殊用途保护内存
系统内存外部堆(可能多个) 目前用于金鱼
系统-康核 连续主内存;仅用于没有 SysmemContiguousPool 的系统

并非所有堆都会从固定池中进行子分配;例如“核心”和“Contig Core” 可以从主内存分配某些堆直接对应于 fuchsia.sysmem.HeapType 值,但所选的堆也可能是 依赖于 is_physically_contiguousBufferMemorySettings 成员。

系统核心

系统核心从主内存分配。如果不存在 向内存添加约束条件

SysmemContiguousPool

CPU 和系统上的一些其他设备只需要几乎连续的 内存。他们可以选择具有任意实际地址的任意网页,并且依靠 MMU 硬件,用于分配新的连续虚拟地址。这样,您就可以 因为任何物理页面都可以使用

但是,某些硬件不具备 MMU 或分散-收集功能。这样 硬件需要物理上连续的地址空间 在内存中的顺序是相同的。在系统运行时,主内存 变得越来越分化, 因为其他分配的页面恰好 随机分布在内存周围。

为了避免这个问题,Sysmem 提供了一个单独的连续池。它 在启动后不久分配一个大型内存池, 然后再向应用提供较小的部分。从理论上讲, 内存仍可能碎片化,但实际上它能发挥作用, 更大的内存块从该池中分配,而同一集群中 数据块会同时释放回数据池。

SysmemAmlogicProtectedPool

在使用 Amlogic SoC 的系统中,DRM(受保护的内存)视频需要 通过访问控制机制分配给特殊区域 无法读取解密的视频。这些区域必须 并且只能由 GPU 和其他硬件在特殊模式下访问, 硬件以有线方式连接,以确保其不会泄露内存。

不能将内存任意标记为受保护或不受保护。硬件 只能将少量 (< 32) 区域标记为受保护。为此, 系统内存可以在启动后不久分配受保护的池(类似于 并告知固件保护该池中的所有内存 区域。然后它可以从这个受保护的内存池中进行子分配。

tee_secure

tee_secure 用于另一种类型的受保护的内存, 数据类型。固件分配此区域, ZBI 必须告诉 zircon 从内存中分配,也绝不接触它其他驾驶员 可以检索有关该存储器的信息及其所在位置 然后告知 sysmem。系统可以通过以下方式从此堆进行子分配: 所需的资源。

系统内存外部堆

外部堆不一定使用实际内存。例如,金鱼 堆是外部堆,表示 FEMU 之外的视频内存 虚拟机。客户端可以传递 VMO 句柄,但不应传递 直接写入内存;而是让 goldfish 驱动程序查找主机 使用 VMO KOID 管理资源

VMO 层次结构

系统使用 VMO 的层次结构来跟踪 客户。让 VMO 保持活跃状态的因素有三个:

  1. VMO 的句柄。

  2. VMO 到进程地址空间的映射。

  3. 表示已映射到设备的 PMT

出于安全考虑,sysmem 无法回收内存供 VMO 使用 直到所有这些类型的引用都消失普通 对于 VMO,内核通过仅在所有引用对象被销毁后销毁 VMO 都消失了。不过,sysmem 会从较大的物理地址子分配 VMO 因此它需要了解 VMO 是否被销毁, 决定要重复使用哪些内存范围。

内核支持 ZX_VMO_ZERO_CHILDREN 信号来帮助完成这些工作 用例 - 如果 VMO 的所有子项都已关闭,则 ZX_VMO_ZERO_CHILDREN 将在父级 VMO 上收到信号。

VMO 层次结构

客户端叶 VMO

这些是分发给客户端的 VMO;调用 BufferCollection.SetName,然后再分配 VMO。客户 也可以直接在 VMO 上设置 ZX_PROP_NAME,但我们不建议这样做 因为 sysmem 驱动程序无法访问该名称。

系统还会保留对这些 VMO 的引用,但前提是 BufferCollection 会继续引用它们,即使当前没有子级 VMO 句柄

中间 VMO

每个叶 VMO 都有一个中间 VMO 作为父 VMO。两者之间存在 1-1 映射关系 叶和中间 VMO。名称由堆设置,通常固定不变 来自堆的所有 VMO例如,对于 来自连续池的 VMO。

系统使用这些 VMO 检测是否清除了对叶 VMO 的所有引用 输出;一旦收到 ZX_VMO_ZERO_CHILDREN 信号,便知道它是安全的 让它删除 VMO 并可能重复使用该空间中间 VMO 从未 会传递到 sysmem 进程之外,因此客户端永远无法引用它们 。

堆 VMO

它们表示为堆中的 VMO 分配的整个内存池 。它们通常会在启动后不久进行分配,以确保有足够的内存 可用。堆 VMO 也可能表示 地址 - 例如 tee_secure 覆盖特定的物理范围 由引导加载程序分配。

中间 VMO 作为堆 vmo 中的切片分配,因此 每个中间 VMO 表示堆中不同的内存范围

如果堆不代表物理内存池,则不需要 堆 VMO。在这种情况下,中间 VMO 是在没有父 VMO 的情况下分配的。

报告内存

检查

Sysmem 会提供 Inspect 层次结构,以将其内存用量报告给 快照和其他客户端应用下面是一个简单的层次结构示例:

  root:
    sysmem:
      collections:
        logical-collection-0:
          allocator_id = 1
          heap = 0
          min_coded_height = 1024
          min_coded_width = 600
          name = vc-framebuffer
          pixel_format = 101
          pixel_format_modifier = 0
          size_bytes = 2490368
          vmo_count = 1
          collection-5:
            channel_koid = 20048
            debug_id = 5498
            debug_name = driver_host
          collection-6:
            channel_koid = 20050
            debug_id = 5498
            debug_name = driver_host
          collection-at-allocation-7:
            debug_id = 19829
            debug_name = virtual-console.cm
            min_buffer_count = 1
          collection-at-allocation-8:
            debug_id = 5498
            debug_name = driver_host
          collection-at-allocation-9:
            debug_id = 5498
            debug_name = driver_host
          vmo-20085:
            koid = 20085
      heaps:
        SysmemContiguousPool:
          allocations_failed = 0
          allocations_failed_fragmentation = 0
          free_at_high_water_mark = 37498880
          high_water_mark = 2490368
          id = 1
          is_ready = true
          last_allocation_failed_timestamp_ns = 0
          max_free_at_high_water = 37498880
          size = 39989248
          used_size = 2490368
          vmo-20085:
            koid = 20085
            size = 2490368
        SysmemRamMemoryAllocator:
          id = 0

系统通过检查层次结构来报告其内存视图, /dev/diagnostics/class/sysmem/XXX.inspect 文件(其中 XXX 是伪随机文件, 3 位数标识符)。显示的每个逻辑集合都代表一组相同的 缓冲区。这些逻辑集合包含列表 该合集中由直播中间 VMO 组成的组合。 并且可用于唯一标识系统中的系统内存虚拟机 memgraph 输出。

所有堆还具有检查节点。其中包括 所有子 VMO 以及堆的满满程度以及 它的任何分配失败。有些堆只有名称和 ID 属性, 而不是从它们分配的 VMO 的信息。

逻辑集合的 allocator_id 与所用堆的 id 匹配 来分配其内存。

检查数据受到限制,因为系统内存无法查看其他 进程。例如,它不知道还有哪些其他进程, 保留对其 VMO 的引用,只不过至少有一个进程。 它也不知道创建了 VMO 的客户端进程的确切名称。 系统客户端应使用其 但并不强制执行,也无法保证 客户端设置的名称正确无误

不过,有些信息 检查数据。例如,客户端进程可以保留某个通道 而无需保留 VMO 的任何句柄。仅限 sysmem 知道 BufferCollection 通道与内部 VMO 之间的映射 过程。channel_koid 属性提供有关服务器上的信息 频道 ID。

ZX_INFO_PROCESS_VMOs

此系统调用由 memgraphmem 工具使用。它可以确定 进程引用 VMO,这对于将内存归因于指定的 安全地向流程发送消息

sysmem 使用的 VMO 层次结构可能会导致这些工具出现问题。对于 例如,mem 会忽略不含任何已提交的 VMO 内存(分配的内存,有物理内存支持),以免杂乱无章 输出内容。这会导致 mem 忽略叶 VMO,因为它是 Cloud Storage 中的根 VMO 实际分配内存的树。Mem 有一些可传播的技巧 作为内部 IP 地址的子项的 VMO 的 SysmemContiguousPoolSysmemAmlogicProtectedPool - 查看 "size" [尺寸]叶 VMO 的一部分,并假设已分配所有内存。这个 仅适用于分配没有重叠(即没有重叠)的固定大小池 为什么它被限制在一组硬编码的池中。

外部堆 VMO 也很复杂,因为它们实际上不会占用 客户机虚拟机内的内存。因此,内存负责执行 正确做法是不报告这些错误(其承诺的内存大小为 0), 这意味着很难将主机系统上的内存归因于 内部环境

memgraph -v 对内存信息的处理较少,但用户 需要自行处理以确定内存用量。它还可以是 难以确定 VMO 有哪些来源,因为它们 必须有一致的名称

统一的方法

任何想要完整而准确地了解系统内存 VMO 的实用程序都必须 合成检查和 ZX_INFO_PROCESS_VMOS 信息。系统检查 数据应该是存在哪些系统内存 VMO 的可信来源,而内核 是进程保留对 VMO 的引用的可信来源。这会 需要遍历逻辑缓冲区集合条目并列出它们 然后通过ZX_INFO_PROCESS_VMOS查找它们的尺码 哪些进程引用了其子项。

实用程序可以为每个进程截取 ZX_INFO_HANDLE_TABLE 快照。然后它可以 使用该表在 channel_koid 中查找 koid,以确定哪个 即保留该 BufferCollection

在某些情况下,无法正确计算内存。通过 主要问题是,系统不会报告频道消息中保留的标识名 这就使我们无法对这些引用进行解释客户 可以将 VMO 标识名推送到某个频道,并且永远不会从该频道读取数据; 就连内核也不知道将内存归因于谁。调试 在这种情况下,您可以使用客户端信息作为后备。

未来可能发生的变化

  • 为每个客户端创建一个中间 VMO,以便系统内存可以自行确定 客户端仍然有对 VMO 的引用。

  • 让组件框架改为向 sysmem 传递不可伪造的标识符 就是让客户端传递可伪造的调试名称