1

考虑具有 4 GB RAM内存的32 位 x86 Linux系统,因此如书籍以及许多论坛中所述,内存映射如下:

  1. 内核逻辑地址-最多896 MB - 一对一映射,可以使用kmalloc()分配。
  2. 内核虚拟地址- 128MB(高于 896MB - 内核逻辑地址) - 使用vmalloc()分配并分配虚拟连续但物理(分散在RAM中)非连续内存页面。

我无法完全理解并需要澄清的几点。

  1. 我的理解是,当kmalloc()用于分配内存时,它总是来自 RAM 中的 0 到 896MB,而不是超出这个范围。

  2. 当我们使用vmalloc()分配内存时,分配的内存是否在 RAM 内从 896MB 到 4GB 范围内?还是仅在 RAM 内从 896MB 到 1GB 范围内分配?

  3. 当我们说内核只有 1GB 的虚拟地址空间时,这是否意味着内核无法访问超过 1GB 的 RAM?如果可以,那么它是如何完成的?128MB 的内核虚拟地址空间是否用于此目的?

请帮忙。

4

1 回答 1

2

理论上有 3 种不同的“内存管理器”。一个管理物理 RAM(主要跟踪空闲物理 RAM 的页面),一个管理虚拟空间(映射到每个虚拟地址空间的内容,使用固定大小的片段 - 页面大小),第三个管理“堆”(允许将更大区域的虚拟地址空间分成任意大小的块)。

起初; Linux 内核试图使用它的内核“堆”来管理所有这三个非常不同的东西。通过将“所有 RAM”线性映射到内核空间,它们绕过了管理内核虚拟内存的需要,最终在内核空间中的虚拟地址和物理地址之间建立了简单的关系(例如“物理 = 虚拟 - 基址”),并通过分配“堆”您还分配物理内存。

最初这很好,因为当时计算机很少有超过 128 MiB 的 RAM(Linus 并不希望内核存在很长时间,因为 GNU 计划“很快”切换到 Hurd),并且内核空间非常大大于“所有 RAM”。随着 RAM 数量的增加,它变成了一个问题——“所有 RAM”变得比内核空间大,所以“使用堆来管理 3 个非常不同的东西”是行不通的。

当然,一旦出现问题,很多内核代码都依赖于“kmalloc 分配物理内存”,因此很难解决问题。相反,他们将物理内存分成 2 个区域 - 一个由“kmalloc”管理的区域和另一个由“vmalloc”管理的区域;然后更改内核部分以使用“vmalloc”而不是“kmalloc”,这样很容易进行这些更改。

  1. 我的理解是,当 kmalloc() 用于分配内存时,它总是来自 RAM 内的 0 到 896MB,而不是超出这个范围。

是的; 这是物理内存的第一个区域,它适合“kmalloc”使用的内核空间映射。

  1. 当我们使用 vmalloc() 分配内存时,分配的内存是否在 RAM 内从 896MB 到 4GB 范围内?还是仅在 RAM 内从 896MB 到 1GB 范围内分配?

它将从不在第一个区域(“896MB 或更高”范围内的任何位置)中的任何 RAM 分配。

  1. 当我们说内核只有 1GB 的虚拟地址空间时,这是否意味着内核无法访问超过 1GB 的 RAM?如果可以,那么它是如何完成的?128MB 的内核虚拟地址空间是否用于此目的?

内核的 1 GiB 虚拟空间;一些(896MB)将是物理地址空间的线性映射,一些将是内存映射(PCI)设备,还有一些将被留作可以进行动态映射的区域。对于“vmalloc”,内核将分配 RAM 的物理页面,然后将它们映射到“动态映射区域”(并返回与其物理地址无关的指向映射位置的指针,并打破“物理 = 虚拟 -基”关系)。

注意 1:确切的大小/限制是可变的 - 例如,内核可以编译为“2 GiB / 2 GiB 拆分”,其中内核空间为 2 GiB(而不是“3 GiB / 1 GiB 拆分”);并且“kmalloc 区域”的大小可能取决于各种因素(PCI 设备需要多少空间、有多少 RAM 等),并且可能不是 896MB。

注2:由于引入了“vmalloc”来解决原来的问题;计算机切换到 64 位(“所有内存”可以/确实再次适合内核空间),并且“vmalloc”变得不必要(并且可能只是落入“kmalloc”)。然而,发生了许多其他变化(NUMA 的引入、加密 RAM、非易失性 RAM ......;加上任何一个人都无法追踪的更多安全漏洞),所以最初的设计缺陷已经达到了暂时的“坏主意,但是,如果我们继续为安全漏洞添加变通方案,技术上仍然不会被破坏”阶段(直到 RAM 和非易失性 RAM 的大小不可避免地增加,并且在未来的某个时候再次需要“vmalloc”——可能在大约 30 年内)。

于 2019-11-13T17:23:57.173 回答