5

在我读过的几乎所有关于 Linux 内核中的 HIGHMEM 的书籍和文章中,他们都说在使用 3:1 拆分时,并非所有 1GB 都可用于内核进行映射。通常它是 896MB 左右,其余的用于内核数据结构、内存映射、页表等。

我的问题是,这些数据结构到底是什么?页表通常是通过页表地址寄存器访问的,对吧?页表的基地址通常存储为物理地址。现在为什么需要为整个表保留一个虚拟地址空间?

同样,我读到内核代码本身占用空间。这与虚拟地址空间有什么关系?这不是存储代码所消耗的物理内存吗?

最后,这些数据结构为什么要预留 128MB 的空间呢?为什么不能根据需要在整个 1GB 地址空间中使用它们,就像内核中的任何其他普通数据结构一样?

我已经阅读了 LDD3、Professional Linux Kernel Architecture 和 stack-overflow 上的几篇文章(例如:Why Linux Kernel ZONE_NORMAL is limited to 896 MB?)和一篇较早的 LWN文章,但没有找到相关的具体信息。

4

2 回答 2

4

关于页表,MMU 确实不会关心页表本身是否映射到虚拟地址空间中——出于地址转换的目的,那是可以的。但是当内核需要修改页表时,它们确实需要映射到虚拟地址空间中——内核不能只是“及时”映射它们,因为它需要自己修改页表来做那。这是一个先有鸡还是先有蛋的问题,这意味着页表需要始终保持映射。

内核代码也存在类似的问题。对于要执行的代码,它必须映射到虚拟地址空间中——如果进行页表修改的代码本身不存在,我们就会遇到类似的先有鸡还是先有蛋的问题。鉴于此,将整个内核代码与内核模式堆栈和任何内核数据结构一起通过代码访问更容易,因为您不想潜在地出现页面错误。这种数据结构的一个大例子是结构数组struct page,代表每个物理内存页。

于 2012-07-23T04:22:34.943 回答
1

128MB 的预留空间不用于始终使用它的特定数据结构。
它是虚拟内存,保留给可能使用它的各种用户。通常,它不会全部使用。

关于物理内存和虚拟内存:每次分配都需要三件事——物理页面、虚拟页面和连接两者的映射。Linux 几乎从不直接使用物理地址,它总是通过虚拟地址转换。
对于大多数内核内存分配(称为lowmem),这种转换非常简单——从虚拟地址中减去一些常数以获得物理地址。但是,仍然使用虚拟地址。

Linux 的内存管理是在虚拟内存空间(4GB)远大于物理内存时编写的,即使在最大的机器上也是如此。在这种情况下,浪费虚拟地址不是问题。今天,当物理内存很大时,这会导致效率低下和问题。

任何调用者都使用vmalloc虚拟地址范围vmalloc。例如:
1. 加载内核驱动程序(使用modprobeinsmod)。
2. 内核模块经常用vmalloc. 替代函数kmalloc过去被限制为 128K,它会将大小向上舍入为 2 的幂,因此vmalloc通常首选用于大分配。

于 2012-07-19T13:41:07.073 回答