【问题标题】:What data structures use 128MB of 1GB Linux kernel space?哪些数据结构使用 128MB 的 1GB Linux 内核空间?
【发布时间】:2012-07-18 00:08:01
【问题描述】:

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

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

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

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

我已经阅读了 LDD3、专业 Linux 内核架构和 stack-overflow 上的几篇文章(例如:Why Linux Kernel ZONE_NORMAL is limited to 896 MB?)和一个较旧的 LWN article,但没有找到关于相同的具体信息。

【问题讨论】:

    标签: memory-management linux-kernel virtual-memory


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 如果128MB不是为特定的数据结构保留的,为什么我们不能使用整个1G kernel-virtual-space来映射到某个虚拟地址?这样,如果系统正好有 1GB 物理内存,则根本不需要使用 HIGHMEM。在基于 896MB 的设置中,需要 HIGHMEM 来利用任何大于 896MB 的物理内存。同样,当我们为某些东西保留 128MB(甚至不使用它)时,vmalloc 无法使用那么多虚拟地址范围。正如你所说,一切都是通过虚拟地址访问的。他们为什么要白白浪费任何虚拟地址?
    • @codetwiddler,这很复杂......浪费虚拟地址是不好的,但它不是没有的。基本点是有两种方法可以将虚拟地址连接到物理地址 - 直接映射(lowmem)和任意动态映射(vmalloc)。每个都必须使用单独的虚拟地址范围,因此它们不会发生冲突。
    • 同意一切,我知道有两种方法及其用途。现在,具体来说,如果我有 1GB 的物理内存,我需要使用 HIGHMEM 来访问超过 896MB 的空间,因为保留了 1GB-896MB 的块。这样做的目的是什么,它有多复杂?该保留应该有一些结构或与该空间相关联的东西,或者至少有一个指向它的指针,我认为如果该保留是静态进行的,它应该是一个非常重要的实体。
    • 另外,在您之前的回答中,您说“通常情况下,它并没有全部使用。”,在这里您说“但它不是没有用的”。不幸的是,这让我有点困惑。
    • 这里详细解释lowmem/vmalloc对我来说太多了。对不起。关于你的困惑——紧急出口通常不被使用,但它们也不是无缘无故的。 128M的vmalloc空间也正常不用。然而,保留它对于各种意外配置很重要。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2019-03-24
      • 1970-01-01
      • 1970-01-01
      • 2011-05-14
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多