在每个用户进程中映射内核是传统的,通常很好
为什么会这样?这个过程不能单独映射到内存吗?映射内核有什么好处,这不会浪费空间吗?
此外,是否可以从用户空间访问内核空间,为什么我会这样做?
答案 0 :(得分:10)
在每个用户进程中映射内核是传统的,通常很好
因此,当您进行系统调用时,内核不必更改页表以访问它自己的内存。例如,一直映射所有物理内存会使read
系统调用从页面缓存中的任何位置复制内容变得更便宜。
是否可以从用户空间访问内核空间,为什么我会这样做?
通常内核会禁用它。页表条目有user/supervisor bit,它控制是否可以在不在内核模式时使用它(即我认为是3环)。因此,内核可以保留其内存映射,同时仍然保护它免受用户空间的读/写。 (另见this for a diagram of nesting of page directories。)
CPU具有支持这种用例的性能特征:有一个"全局"每个PTE中的位(如果设置)表示即使CR3发生更改(即在内核安装新页表时跨上下文切换),CPU也可以将其保持在TLB中。内核为每个进程中包含的内核映射设置了这个。
而BTW,这些内核映射可能只有一个表的物理副本,每个不同的用户空间页表树的顶层页面映射4级表(PML4)只是指向相同的内核PDPTE结构(大部分/全部实际上是1GiB巨页映射,而不是指向更多级别的条目)。请参阅上面链接的图表。
内核允许用户空间读取(并执行)实际上有少量内存:内核将几个4k页called the VDSO area映射到每个进程的地址空间(在非常顶级的虚拟内存。)
对于一些简单但常见的系统调用,例如gettimeofday()
和getpid()
,用户空间可以call
在这些页面中运行(例如,运行rdtsc
并缩放由内核导出的常量导致)而不是使用syscall
进入内核模式并在那里做同样的事情。这样可以节省50到100个时钟周期,以便在现代x86 CPU上进行内核模式的往返,更多的是在发送到正确的系统调用之前不需要在内核中保存/恢复所有内容。
是否可以在不映射内核的情况下将进程映射到内存中?
在64位内核上使用32位进程,整个4GiB虚拟地址空间可用于用户空间。(除了3个左右的4k VDSO页面。)
否则(当用户空间虚拟地址与内核空间虚拟地址一样宽时)Linux将上半部分用于所有物理内存的内核映射(在x86上使用1G largepages)。
i386 Linux有一个配置选项,可以分割1:3,IIRC,进一步限制内核,但允许更多的虚拟地址空间用于用户空间进程。 IDK,如果这对于其他体系结构上的32位内核是常见的,或者只是x86。
这不会浪费空间吗?
它占用了一些虚拟地址空间,但是你应该拥有比物理内存更多的虚拟地址空间。如果你不这样做,你必须支付更频繁地重新映射内存的速度成本。
这就是我们拥有x86-64的原因,因此虚拟地址空间 large 。 48位是256 TiB,因此其中一半是128 TiB的地址空间。如果必要/有用,未来的CPU可以为更广泛的虚拟地址实现硬件支持。 (The page table format supports up to 52 bit physical addresses.)。对于提供密度高于DRAM的内存映射存储的非易失性DIMM而言,这可能会成为一个问题,并且有理由使用这两种地址空间。
如果在一个进程中需要超过2GiB的虚拟地址空间,请使用64位系统。 (或者如果你需要一个极好的进程/线程,至少使用一个64位内核。有时PAE的32位内核会遇到内存分配问题。请参阅一些https://serverfault.com/个问题。)
某人reposted on their blog some of Linus Torvalds' comments about PAE (Physical Address Extensions)允许在32位x86系统上拥有超过4GB的物理内存。总结:哎呀,即使有一个很好的内核端实现,它肯定比64位内核慢。除了英特尔工程师更多有趣的侮辱之外,他们认为这对于32位操作系统来说是一个好主意并解决问题。