![Linux 上的高内存和低内存是什么?](https://linux22.com/image/42527/Linux%20%E4%B8%8A%E7%9A%84%E9%AB%98%E5%86%85%E5%AD%98%E5%92%8C%E4%BD%8E%E5%86%85%E5%AD%98%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F.png)
我对 Highmem 和 Lowmem 之间的区别感兴趣:
- 为什么会有这样的差别呢?
- 这样做我们能得到什么?
- 各有什么特点?
答案1
在 32 位架构上,寻址 RAM 的地址空间范围为:
0x00000000 - 0xffffffff
或4'294'967'295
(4 GB)。
Linux 内核将其 3/1 (也可能是 2/2 或 1/3 1)分别分成用户空间(高内存)和内核空间(低内存)。
用户空间范围:
0x00000000 - 0xbfffffff
每个新生成的用户进程都会在该区域内获得一个地址(范围)。用户进程通常是不可信的,因此被禁止访问内核空间。此外,它们被认为是非紧急的,作为一般规则,内核尝试推迟向这些进程分配内存。
内核空间范围:
0xc0000000 - 0xffffffff
内核进程在这里获取其地址(范围)。内核可以直接访问这 1 GB 地址(当然,不是完整的 1 GB,还有 128 MB 保留用于高端内存访问)。
在内核空间中生成的进程是可信的、紧急的并且假定没有错误,内存请求会立即得到处理。
如果愿意,每个内核进程也可以访问用户空间范围。为了实现这一点,内核将用户空间(高位内存)的地址映射到内核空间(低位内存),上面提到的 128 MB 是专门为此保留的。
1分割是3/1、2/2还是1/3由CONFIG_VMSPLIT_...
选项控制;您可以检查一下,/boot/config*
看看为您的内核选择了哪个选项。
答案2
第一个参考文献是Linux 设备驱动程序(可在线或以书籍形式获取),特别是第15章其中有一个关于该主题的部分。
在理想的情况下,每个系统组件都能够映射它需要访问的所有内存。 Linux 和大多数操作系统上的进程都是这种情况:32 位进程只能访问略小于 2^32 字节的虚拟内存(实际上,在典型的 Linux 32 位架构上约为 3GB)。对于内核来说,这变得很困难,它需要能够映射正在执行系统调用的进程的完整内存,加上整个物理内存,以及任何其他内存映射的硬件设备。
所以当32位内核需要映射超过4GB内存时,必须编译为高内存支持。高端内存是没有永久映射到内核地址空间的内存。 (低内存则相反:它总是被映射,因此您只需通过取消引用指针即可在内核中访问它。)
当您从内核代码访问高位内存时,您需要kmap
首先调用,以从页数据结构()中获取指针struct page
。kmap
无论页面位于高内存还是低内存,调用都有效。还有kmap_atomic
一种增加了约束,但在多处理器机器上效率更高,因为它使用更细粒度的锁定。通过获得的指针kmap
是一种资源:它占用了地址空间。一旦完成,您必须调用kunmap
(或kunmap_atomic
) 来释放该资源;那么该指针就不再有效,并且在再次调用之前无法访问该页面的内容kmap
。
答案3
这与Linux内核有关;我不确定 Unix 内核是如何处理这个问题的。
高内存是用户空间程序可以寻址的内存段。它不能触及低内存。
低内存是 Linux 内核可以直接寻址的内存段。如果内核必须访问高端内存,它必须首先将其映射到自己的地址空间。
最近推出了一个补丁,可以让您控制片段的位置。权衡是您可以从用户空间中取出可寻址内存,以便内核可以拥有更多在使用前不必映射的内存。
其他资源:
答案4
对于那些在 Linux 内核内存空间上下文中寻找解释的人来说,请注意两个相互矛盾的定义高/低内存分割(不幸的是没有标准,必须在上下文中解释):
“高端内存”定义为内核空间的总和虚拟的记忆。这是一个只有内核可以访问的区域,包含所有大于或等于 的虚拟地址
PAGE_OFFSET
。因此,“低内存”指的是剩余地址的区域,其对应于每个用户进程可访问的用户空间内存。例如:在默认为 的 32 位 x86 上
PAGE_OFFSET
,这意味着高端内存是任何地址ADDR
(ADDR ≥ 0xC0000000 = PAGE_OFFSET
即更高的 1 GB)。这就是 Linux 32 位进程通常限制为 3 GB 的原因。注意
PAGE_OFFSET
不能直接配置,依赖于可配置VMSPLIT_x
选项(来源)。总结一下:在 32 位架构中,虚拟内存默认分为较低的 3 GB(用户空间)和较高的 1 GB(内核空间)。
对于 64 位,
PAGE_OFFSET
不可配置,并且取决于有时在内核加载期间运行时检测到的架构细节。在 x86_64 上,
PAGE_OFFSET
用于0xffff888000000000
4 级分页(典型)和0xff11000000000000
5 级分页(来源)。对于 ARM64,这通常是0x8000000000000000
.但请注意,如果启用了 KASLR,则该值是故意不可预测的。
“高级内存”定义为身体的无法与内核虚拟内存的其余部分连续映射的内存。内核虚拟地址空间的一部分可以作为单个连续块映射到所谓的物理“低内存”中。要完全理解这意味着什么,需要对 Linux 虚拟内存空间有更深入的了解。我建议通过这些幻灯片。
从幻灯片来看:
这种“高/低内存”划分仅适用于安装的物理 RAM 大小相对较高(超过约 1 GB)的 32 位架构。否则,即当物理地址空间较小(<1GB)或虚拟内存空间较大(64位)时,可以从内核虚拟内存空间访问整个物理空间。在这种情况下,所有物理内存都被视为“低内存”。
最好根本不存在高端内存,因为整个物理空间可以直接从内核访问,这使得内存管理更加简单和高效。这在处理 DMA(通常需要物理上连续的内存)时尤其重要。
另请参阅@gilles 的回答