地址空间

在操作系统中 内存管理 提供了为进程动态分配部分内存的方法, 以便在不再需要时将其释放,以便重复使用。 现代操作系统使用地址空间来隔离进程内存。

地址空间 表示进程用来引用内存的一组虚拟地址。 虚拟地址直接映射到实际地址。Fuchsia 使用 VMAR (虚拟内存地址区域)来表示地址空间。

VMAR、映射和 VMO

在 Fuchsia 中,每个进程都有一个根 VMAR,并且可以划分为 VMAR 和映射。映射指向 VMO(虚拟内存对象)

显示根 VMAR、子 VMAR、映射和 VMO

VMAR 和虚拟机映射

通过 VMAR 是特定进程中连续的虚拟地址范围”地址 空格:

  • VMAR 可以有非重叠的子 VMAR 和/或虚拟机映射 次级区域
  • 它们会将保护位应用于一部分内存(读写、 可执行文件等)
  • 它们有一个 WAVL 树, 提高搜索效率

虚拟机映射表示“已映射”即虚拟地址空间中的 由实体页面支持的地址:

  • 虚拟机映射没有子级
  • 他们从 VMO 映射一系列页面
  • 成功的网页搜索到此结束

以下是可用的 VMAR 和虚拟机映射系统调用:

另请参阅虚拟内存地址区域参考

VMOS

VMO 是内存字节的容器。 它们包含可通过虚拟机映射映射到地址空间的物理页面。 以下是 VMO 系统调用:

另请参阅虚拟内存对象参考

虚拟内存管理器 (VMM)

虚拟内存管理器 (VMM) 负责维护进程地址 包括:

  • 为 已映射。
  • 确保为地址范围设置了正确的访问保护位。

为此,它会管理 VMAR、虚拟机映射、VMO 和 硬件页面表格。另请参阅 VMM 源代码

当进程开始时,其整个地址空间表示为一个 VMAR。 由于地址空间的不同部分已映射,因此 VMAR 层次结构树 填充。树中的节点以 VMAR 和 VM 的形式创建并销毁 系统会创建和销毁映射。

节点表示 VMAR 或虚拟机映射:

  • VMAR 指向一系列子项,这些子项是其他 VMAR 和虚拟机 在父级 VMAR 的地址范围内的映射。
  • 虚拟机映射指向一个 VMO 内映射到该 指定地址范围

详细了解 直观呈现根 VMAR 中的内存用量

VMM 使用 地址空间布局随机化 用于控制在地址空间内创建新 VMAR 的地址范围。 通过 aslr.entropy_bits 内核命令行选项可用于控制熵的位数 随机生成。更高的熵会产生更加稀疏的地址空间, 更加广泛地使用 VMAR 和虚拟机映射。

物理内存管理器 (PMM)

通过 物理内存管理器 (PMM) 将系统上的所有可用物理内存 (RAM) 划分到页面中, 管理它们的后续情况 当出现以下情况时,它负责为 VMO 提供免费的物理页面 他们需要它们。

VMO 是按需求调出的,即系统会按需填充(提交)其网页。 页面会在写入时被提交。在此之前,未提交的页面 由系统上的单例物理零页面表示。这样可以避免 不必要地为尚未访问的页面或仅 所有来源。

VMO 也可以由 用户空间分页器, 它会按需填充 VMO 中的特定内容, 例如从磁盘上的文件中读取的内容 了解如何编写用户寻呼机

示例:映射 VMO

如需映射 VMO,请执行以下操作:

  1. 使用 zx_vmar_root_self() 获取进程根 VMAR 的句柄。 例如:

    zx_handle_t vmar = zx_vmar_root_self();
    
  2. 使用 zx_vmo_create(...) 创建 VMO。 这将返回 VMO 句柄,例如:

    const size_t map_size = zx_system_get_page_size();
    zx_vmo_create(map_size, 0, &vmo);
    
  3. 使用zx_vmar_allocate(...) 在父级 VMAR 中创建子级 VMAR。 这将返回一个 VMAR 句柄及其起始地址,例如:

    const size_t region_size = zx_system_get_page_size() * 10;
    zx_vmar_allocate(vmar, ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE, 0,
                     region_size, &region, &region_addr);
    

    这是可选步骤;您还可以将 VMO 直接映射到父级。

  4. 使用 zx_vmar_map(...) 在 VMAR 中映射 VMO。 此命令会返回现在映射到 VMAR 的 VMO 的起始地址 示例:

    zx_vmar_map(region, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo, 0,
                map_size, &map_addr);
    

显示 VMO 到根 VMAR 的映射

示例:访问 VMO 映射

在前面的示例中, 假设 zx_vmar_map() 返回了 map_addr 0x4000。 要访问映射地址 0x4000,请执行以下操作: 代码可能如下所示:

zx_vmar_map(...&addr); // addr = 0x4000
auto arr = reinterpret_cast<int*>(addr);
arr[0] = 1; // page fault

指针解引用会导致页面错误。 要解决页面错误,内核将执行以下操作:

  1. 在启动进程的 VMAR 树中搜索地址 0x4000 在 root_vmar 处,直到找到包含该地址的虚拟机映射。
  2. 虚拟机映射将包含对 VMO 的引用, 以及 VMO 页面列表中的偏移量 (对应于映射的第一个地址)。 查找与地址 0x4000 对应的 VMO 偏移量。
  3. 如果 VMO 在该偏移量处没有页面,则分配一个新页面。 假设此网页的实际地址是 0xf000。
  4. 添加从虚拟地址 0x4000 到实际地址 0xf000 的转换 通过 ArchVmAspace、 表示针对特定架构的页表 用于跟踪 MMU

显示 VMO 地址在 VMAR 地址范围内