linux内核如何管理不到1GB的物理内存?
Posted
技术标签:
【中文标题】linux内核如何管理不到1GB的物理内存?【英文标题】:How does the linux kernel manage less than 1GB physical memory? 【发布时间】:2011-05-30 12:55:05 【问题描述】:我正在学习 linux 内核内部结构,在阅读“理解 Linux 内核”时,我遇到了很多与内存相关的问题。其中之一是,如果我的系统上安装了 512 MB 的物理内存,Linux 内核如何处理内存映射。
据我所知,内核将 0(或 16)MB-896MB 物理 RAM 映射到 0xC0000000 线性地址并可以直接寻址。所以,在上述我只有 512 MB 的情况下:
内核如何从 512 MB 映射到 896 MB?在所描述的方案中,内核进行了设置,以便每个进程的页表将虚拟地址从 0xC0000000 直接映射到 0xFFFFFFFF (1GB) 到物理地址从 0x00000000 到 0x3FFFFFFF (1GB)。但是,当我只有 512 MB 物理 RAM 时,如何将虚拟地址从 0xC0000000-0xFFFFFFFF 映射到物理 0x00000000-0x3FFFFFFF ?重点是我的物理范围只有 0x00000000-0x20000000。
在这种情况下如何处理用户模式进程?
每篇文章都只解释这种情况,当您安装了 4 GB 内存并且内核将 1 GB 映射到内核空间并且用户进程使用剩余的 RAM 量时。
如果能帮助我加深理解,我将不胜感激。
谢谢..!
【问题讨论】:
这对 unix.stackexchange.com 来说是个好问题 虚拟地址内核内存映射到不一定是0xC0000000。 0xC0000000 是 x86 的默认地址 osgx,感谢您的 cmets。绝对有用。需要理解您提供的指针。如果有问题,会回来。非常感谢。 TheLoneJoker,我还可以向您推荐 Robert Love 的《Linux 内核开发》一书。它由文本组成,而不是由代码和 cmets 组成,就像 ULK 一样 【参考方案1】:并非所有虚拟(线性)地址都必须映射到任何东西。如果代码访问未映射的页面,则会引发页面错误。
物理页面可以同时映射到多个虚拟地址。
在 4 GB 虚拟内存中有 2 个部分:0x0... 0xbfffffff - 是进程虚拟内存,0xc0000000 .. 0xffffffff 是内核虚拟内存。
内核如何从 512 MB 映射到 896 MB?它映射到 896 MB。因此,如果您只有 512 个,则映射的只有 512 MB。
如果您的物理内存位于 0x00000000 到 0x20000000 中,它将被映射以供内核直接访问虚拟地址 0xC0000000 到 0xE0000000(线性映射)。
在这种情况下用户模式进程如何?用户进程的物理内存将被映射(不是顺序的,而是随机的页到页映射)到虚拟地址 0x0 .... 0xc0000000。此映射将是 0..896MB 页面的第二个映射。这些页面将从免费页面列表中获取。
物理 RAM 中的用户模式进程在哪里?任何地方。
每篇文章都只解释了当您安装了 4 GB 内存和的情况没有。每篇文章都解释了如何映射 4 Gb 的虚拟地址空间。虚拟内存的大小始终为 4 GB(对于没有内存扩展的 32 位机器,如 x86 的 PAE/PSE/etc)
正如 Robert Love 的书 Linux Kernel Development
(我使用第三版)的 8.1.3. Memory Zones
中所述,物理内存有几个区域:
因此,如果您有 512 MB,您的 ZONE_HIGHMEM 将为空,而 ZONE_NORMAL 将映射 496 MB 的物理内存。
另外,请查看本书的2.5.5.2. Final kernel Page Table when RAM size is less than 896 MB
部分。这是关于内存小于 896 MB 的情况。
另外,对于 ARM,还有一些关于虚拟内存布局的描述:http://www.mjmwired.net/kernel/Documentation/arm/memory.txt
第63行PAGE_OFFSET high_memory-1
是内存的直接映射部分
【讨论】:
osgx,根据您提到的内容,“所以,如果您有 512 MB,您的 ZONE_NORMAL 将映射 496 MB 的物理内存。”如果是这种情况,则物理内存中将不会有任何用户空间页面的位置。除非,可以换出 ZONE_NORMAL 页面?期待你的想法。 @TheLoneJoker,内核可以为用户空间进程分配 phys 页面。区域 ZONE_NORMAL 和 ZONE_HIGHMEM。 (例如linux-mm.org/HighMemory 2G 系统:“内核从两个区域分配进程和页面缓存内存很重要”)如果 ZONE_HIGHMEM 为空,内核将从 ZONE_NORMAL 分配页面。 @TheLoneJoker,交换是虚拟页面上的一个过程,或者,您可以将其命名为“从物理页面取消映射虚拟页面”。因此,虚拟地址空间中的任何用户页面都可以取消映射并换出。 @TheLoneJoker,HIGHMEM 只是内核的问题,对于用户进程,highmem 和法线映射页面之间没有区别。【参考方案2】:硬件提供Memory Management Unit。它是一个能够拦截和更改任何内存访问的电路。每当处理器访问 RAM 时,例如要读取下一条要执行的指令,或者作为由指令触发的数据访问,它会在某个 address 处执行此操作,大致来说,这是一个 32 位值。一个 32 位字可以有超过 40 亿个不同的值,所以有一个 4 GB 的地址空间:这是可以有一个唯一地址的字节数。
因此处理器将请求发送到其内存子系统,如“获取地址 x 处的字节并将其返回给我”。请求通过 MMU,MMU 决定如何处理请求。 MMU 将 4 GB 空间虚拟分割成 页;页面大小取决于您使用的硬件,但典型大小为 4 和 8 kB。 MMU 使用表格告诉它如何处理每个页面的访问:要么授予访问重写地址(页面条目说:“是的,包含地址 x 的页面存在,它是在物理 RAM 地址 y") 或被拒绝,此时内核被调用以进一步处理事情。内核可能决定杀死有问题的进程,或者做一些工作并改变 MMU 表,以便可以再次尝试访问,这次成功。
这是虚拟内存的基础:从这个角度来看,进程有一些RAM,但是内核已经把它移到了硬盘,在“交换空间”中。相应的表在 MMU 表中被标记为“不存在”。当进程访问他的数据时,MMU 调用内核,内核从交换中获取数据,将其放回物理 RAM 中的某个空闲空间,并更改 MMU 表以指向该空间。然后内核跳回到进程代码,就在触发整个事情的指令处。进程代码看不到整个业务,除了内存访问花费了相当长的时间。
MMU 还处理访问权限,防止进程读取或写入属于其他进程或内核的数据。每个进程都有自己的一组 MMU 表,内核管理这些表。因此,每个进程都有自己的地址空间,就好像它独自在一台有 4 GB RAM 的机器上一样——除了该进程最好不要访问它没有从内核正确分配的内存,因为相应的页面被标记缺席或禁止。
当某个进程通过系统调用调用内核时,内核代码必须在该进程的地址空间内运行;因此内核代码必须位于每个进程的地址空间中的某个位置(但受到保护:MMU 表阻止非特权用户代码访问内核内存)。由于代码可以包含硬编码地址,内核最好在所有进程的相同地址;通常,在 Linux 中,该地址是 0xC0000000。每个进程的 MMU 表将地址空间的一部分映射到内核在启动时实际加载的任何 物理 RAM 块。请注意,内核内存永远不会被换出(如果可以从交换空间读回数据的代码本身被换出,事情会很快变糟)。
在 PC 上,事情可能会稍微复杂一些,因为有 32 位和 64 位模式、段寄存器和 PAE(它充当一种具有大页面的二级 MMU)。基本概念保持不变:每个进程都有自己的虚拟 4 GB 地址空间视图,内核使用 MMU 将每个虚拟页面映射到 RAM 中的适当物理位置,或者根本不映射。
【讨论】:
Thomas,内核是在 0xc0000000 的开头还是稍晚一点(几百 MB)? 显然,内核与从 0xC0000000 或不远(例如 0xC0008000)开始的代码链接,至少在 ARM 和 x86 上是这样。然而,内核也使用这 1GB 区域来分配自己的数据,包括动态块 (kmalloc()...
) 和内核内线程的堆栈,我不知道这些地址离高地址有多远......
但0xC0000000-
的前 896 MB 用于映射物理。页?那么,内核存储在非常低的物理地址?
内核必须存储在物理RAM中(内核包含可以从交换区读回东西的代码,所以它不能自己换出,否则谁会从交换空间读回来?)。它在启动期间存储在 RAM 中,此时整个 RAM 不一定可用或完全检测到(这取决于架构;但引导加载程序通常非常原始)。所以内核倾向于去低物理地址。
内核在引导加载程序对其执行 jmp 时存储在低位。但是内核的引导(函数 main 和/或之前)包括移动到更高的地址(在激活 32/64 位模式并检测到内存之后),因为最小的 RAM 用于类似 ISA 的 DMA。内核包含代码和数据;并且可以换出一些数据。原则上,一些代码也可以交换(不是处理页面错误的代码)。 handle_mm_fault 中有一个单独的分支用于内核的虚拟地址。【参考方案3】:
osgx 有一个很好的答案,但我看到有人仍然不明白的评论。
每篇文章仅说明安装 4 GB 时的情况 内存和内核将 1 GB 映射到内核空间和用户 进程使用剩余的 RAM。
这里有很多混乱。有虚拟内存,也有物理内存。每个 32 位 CPU 都有 4GB 的虚拟内存。 Linux 内核的传统划分是 3G/1G 用于用户内存和内核内存,但较新的选项允许不同的分区。
为什么要区分内核空间和用户空间? - 我自己的问题
当任务交换时,必须更新 MMU。对于所有进程,内核 MMU 空间应该保持不变。内核必须随时处理中断和故障请求。
虚拟到物理映射如何工作? - 我自己的问题。
虚拟内存有多种排列方式。
到物理 RAM 页面的单个私有映射。 到单个物理页面的重复虚拟映射。 会引发 SIGBUS 或其他错误的映射。 由磁盘/交换支持的映射。从上面的列表中,很容易看出为什么您可能拥有比物理内存更多的虚拟地址空间。事实上,故障处理程序通常会检查进程内存信息,以查看页面是否映射(我的意思是为进程分配),而不是在内存中。在这种情况下,故障处理程序将调用 I/O 子系统来读取页面。当页面被读取并更新 MMU 表以将虚拟地址指向新的物理地址时,导致错误的进程恢复。
如果您了解上述内容,就会清楚为什么您希望拥有比物理内存更大的虚拟映射。这就是支持内存交换的方式。
还有其他用途。例如,两个进程可能使用相同的代码库。由于链接,它们可能位于进程空间中的不同虚拟地址。在这种情况下,您可以将不同的虚拟地址映射到同一个物理页面,以节省物理内存。这对于新分配很常见;它们都指向物理“零页”。当您触摸/写入内存时,会复制零页并分配新的物理页(COW 或写入时复制)。
有时也可以为虚拟页面设置别名,其中一个为 cached,另一个为 non-cached。可以检查这两个页面以查看哪些数据已缓存,哪些未缓存。
主要是virtual和physical不一样!说起来容易,但在查看 Linux VMM 代码时经常会感到困惑。
【讨论】:
【参考方案4】:-
您好,实际上我不是在 x86 硬件平台上工作,所以我的帖子中可能存在一些技术错误。
据我所知,特别列出了 0(或 16)MB - 896MB 之间的范围,而您的 RAM 多于该数字,例如,您的主板上有 1GB 物理 RAM,这称为“低内存”。如果您的主板上的物理 RAM 超过 896MB,那么其余的物理 RAM 称为 highmem。
说到你的问题,你的板上有 512MiBytes 物理 RAM,所以实际上,没有 896,没有 highmem。
内核能看也能映射的总RAM是512MB。
'因为物理内存和内核虚拟地址是一一对应的,所以内核有512MiBytes的虚拟地址空间。我真的不确定前面的句子是否正确,但这是我的想法。
我的意思是,如果有 512MBytes,那么内核可以管理的物理 RAM 量也是 512MiBytes,而且内核不能创建超过 512MBytes 的这么大的地址空间。
参考用户空间,有一点不同,用户应用程序的页面可以换出到硬盘,但内核的页面不能。
所以,对于用户空间,借助页表等相关模块,似乎还有4GBytes的地址空间。 当然,这是虚拟地址空间,而不是物理 RAM 空间。
这是我的理解。
谢谢。
【讨论】:
【参考方案5】:如果物理内存小于 896 MB,那么 linux 内核会线性映射到该物理地址。
详情见此..http://learnlinuxconcepts.blogspot.in/2014/02/linux-addressing.html
【讨论】:
以上是关于linux内核如何管理不到1GB的物理内存?的主要内容,如果未能解决你的问题,请参考以下文章