找回密码
 立即注册
Qt开源社区 门户 查看内容

Linux 内核如何管理内存

2019-8-22 08:12| 发布者: admin| 查看: 534| 评论: 0

摘要: 在检查了进程的虚拟地址布局之后,我们转向内核及其管理用户内存的机制。 Linux进程在内核中实现为task_struct(进程描述符)的实例。变量mm中的task_struct指向场存储器描述符,结构体为的mm_struct,这是一个程序 ...
在检查了进程的虚拟地址布局之后,我们转向内核及其管理用户内存的机制。



     Linux进程在内核中实现为task_struct(进程描述符)的实例。变量mm中的task_struct指向场存储器描述符,结构体为的mm_struct,这是一个程序的存储器的执行摘要。它存储的开始和存储器段的端部如上述所示,数据结构包括 进程所使用的物理存储器页(RSS代表驻留集大小), 进程使用使用的虚拟地址空间,以及其他。在内存描述符中,我们还找到了用于管理程序内存的两个核心要素:虚拟内存区域集VMA和页表page table。vm记忆区域如下所示:



每个虚拟内存区域(VMA)是一个连续的虚拟地址范围; 这些区域从不重叠。vm_area_struct的一个实例完整地描述了一个内存区域,包括其开始和结束地址,用于确定访问权限和行为的标志,以及用于指定该区域正在映射哪个文件的vm_file字段(如果有)。未映射文件的VMA是称之为匿名的。上面的每个存储器段(例如,堆,堆栈)对应于单个VMA,但存储器映射段除外。虽然在x86机器中很常见,但这不是必需的。VMA并不关心他们所属的segment

      程序的VMA存储在其存储器描述符中,既作为mmap字段中的链接列表,又通过启动虚拟地址排序,以及作为以mm_rb字段为根的红黑树。红黑树允许内核快速搜索覆盖给定虚拟地址的内存区域。当你读取文件/ proc / pid_of_process / maps时,内核只是通过进程的VMA链接列表并打印每个进程。

在Windows中,EPROCESS块大致是task_struct和mm_struct的混合。与VMA模拟的Windows是虚拟地址描述符或VAD ; 它们存储在AVL树中。

4GB虚拟地址空间分为页面。32位模式的x86处理器支持4KB,2MB和4MB的页面大小。Linux和Windows都使用4KB页面映射虚拟地址空间的用户部分。字节0-4095落在第0页,字节4096-8191落在第1页,依此类推。VMA的大小必须是页面大小的倍数。这是4KB页面中3GB的用户空间:



处理器查询页表以将虚拟地址转换为物理存储器地址。每个进程都有自己的一组页表; 每当发生进程切换时,也切换用户空间的页表。Linux 在内存描述符的pgd字段中存储指向进程'页表的指针。对于每个虚拟页面,页面表中对应一个页表条目(PTE),在常规x86分页中是一个简单的4字节记录,如下所示:



      Linux具有读取和设置 PTE中每个标志的功能。位P告诉处理器虚拟页面是否存在于物理内存中。如果清除(等于0),则访问该页面会触发页面错误。请记住,当此位为零时,内核可以使用其余字段执行任何操作。R / W标志代表读/写; 如果清除,页面是只读的。标志U / S代表用户/主管supervise; 如果清除,那么页面只能由内核访问。这些标志用于实现我们之前看到的只读内存和受保护的内核空间。

       D和A位用于脏dirty和访问。脏页面有写入,而被访问页面有写入或读取。两个标志都是粘性的:处理器只设置它们,它们必须由内核清除。最后,PTE存储与该页面对应的起始物理地址,对齐到4KB。它将可寻址的物理内存限制为4 GB。其他PTE字段是其他的用途,这里不详细介绍,比如物理地址扩展

      虚拟页面是内存保护的单位(比如4K) ,因为它的所有字节共享U / S和R / W标志。但是,相同的物理内存可以由不同的页面映射,可能具有不同的保护标志。请注意,在PTE中无处可见执行权限。这就是为什么经典的x86分页允许执行堆栈上的代码,从而更容易利用堆栈缓冲区溢出(仍然可以使用return-to-libc和其他技术来利用非可执行堆栈)。缺少PTE无执行标志说明了一个更广泛的事实:VMA中的权限标志可能会或可能不会干净地转换为硬件保护。内核尽其所能,但最终架构限制了可能的内容。

      需要注意的是 虚拟内存不存储任何内容,它只是将程序的地址空间映射到底层物理内存,后者由处理器作为称为物理地址空间的大块访问。虽然总线上的内存操作有些牵连,但我们可以忽略这一点,并假设物理地址的范围从0到可用内存的顶部,以1字节为增量。该物理地址空间由内核分解为页面帧。处理器不知道或不关心帧,但它们对内核至关重要,因为页面帧是物理内存管理的单位。Linux和Windows在32位模式下都使用4KB页面帧; 这是一个具有2GB RAM的机器的示例:



在Linux中,每个页面帧由描述符和几个标志跟踪。这些描述符一起跟踪计算机中的整个物理内存; 每个页面框架的精确状态始终是已知的。使用伙伴内存分配技术管理物理内存,因此如果可以通过伙伴系统分配页面帧,则它是免费的。分配的页面框架可能是匿名的,保存程序数据,或者它可能位于页面缓存中,保存存储在文件或块设备中的数据。还有其他奇特的页面框架用途,但暂时不管它们。Windows有一个类似的页面帧号(PFN)数据库来跟踪物理内存。

让我们将虚拟内存区域,页表条目和页面框架放在一起,以了解这一切是如何工作的。以下是用户堆的示例:



蓝色矩形表示VMA范围内的页面,而箭头表示将页面映射到页面帧的页面表条目。有些虚拟页面没有箭头; 这意味着他们相应的PTE 清楚地显示Present标志。这可能是因为页面从未被触及或因为它们的内容已被换出。在任何一种情况下,访问这些页面都会导致页面错误,即使它们在VMA内。对于VMA和页面表不同意,这似乎很奇怪,但这种情况经常发生。

VMA就像是程序和内核之间的契约。您要求完成某些事情(分配内存,映射文件等),内核说“确定”,并创建或更新相应的VMA。但它实际上并没有立即兑现请求,而是等待页面错误发生才能真正起作用。内核是一个懒惰的,欺骗性的 这是虚拟内存的基本原理。他看似给你了物理内存,其实没有。它适用于大多数情况,有些是熟悉的,有些是令人惊讶的,但规则是VMA记录已达成一致的内容,而PTE则反映实际已完成的内容由懒惰的内核。这两个数据结构共同管理程序的内存; 两者都在解决页面错误,释放内存,交换内存等方面发挥作用。我们来看一下内存分配的简单情况:



       当程序通过brk()系统调用请求更多内存时,内核只是更新堆VMA并调用它。此时实际上没有分配页面帧,并且新页面不存在于物理内存中。程序尝试访问页面后,处理器页面出现故障并调用do_page_fault()。它使用find_vma()搜索覆盖故障虚拟地址的VMA 。如果找到,则还会针对尝试访问(读取或写入)检查VMA上的权限。 如果没有合适的VMA,该过程会受到Segmentation Fault的惩罚。

        当发现 VMA时,内核必须通过查看PTE内容和VMA类型来处理故障。在我们的例子中,PTE显示页面不存在。事实上,我们的PTE是完全空白的(全为零),在Linux中意味着虚拟页面从未被映射过。由于这是一个匿名VMA,我们有一个纯粹的RAM事务,必须由do_anonymous_page()处理,它分配一个页面框架并使PTE将故障虚拟页面映射到新分配的帧。

         事情可能会有所不同。例如,换出页面的PTE在Present标志中为0,但不是空白。相反,它存储保存页面内容的交换位置,必须从磁盘读取并通过do_swap_page()在所谓的主要故障中加载到页面框架中。

         可以看到,内核非常完美的给每个应用程序一个完整的虚拟地址空间,应用程序无需关心真正的物理地址的分配,就像上图第3步一样,如果它访问的内存地址(虚拟),没有对应的物理内存时候,硬件会自动tigger page fault ,然后内核的的page fault hanlder 自动把PTE 填好,应用程序毫无发觉。(其实有,就是会慢) ,可以通过一些工具来观察每个进程对memory 的管理情况 ,比如发生了多少次page fault 在Linux下面可以使用

cat /proc/PID/stat

在windows 下 大家可以在windows 里面用

按住“Windows+R”打开命令行窗口,输入命令“resmon”,打开资源监视器

里面有个hard fault 列可以观察每个进程发生的page fault 。

这些东西可能对做性能调优的同学比较熟悉




----------------------------------------------------------------------------------------------------------------------
我们尊重原创,也注重分享,文章来源于微信公众号:计算机体系结构及底层原理,建议关注公众号查看原文。如若侵权请联系qter@qter.org。
----------------------------------------------------------------------------------------------------------------------

鲜花

握手

雷人

路过

鸡蛋

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了