说一下虚拟内存
(我们平常说的计算机多大内存,指的就是物理内存)
进程在运行过程中需要访问物理内存,但物理内存是有限的,为了把有限的物理内存分配给不同的进程使用,Linux为每个进程都提供了一个独立的连续的虚拟地址空间,虚拟地址空间与物理内存有着一个映射关系,这个映射关系存储在内核空间中,那么进程访问虚拟内存就是访问物理内存了。(在内核空间中,所有进程的虚拟地址对应的物理地址一样,即内核进程没有自己的地址空间。而在用户空间中,进程具有独立的地址空间,可以防止不同进程之间的数据干扰)
每个进程都有一块连续的虚拟地址空间,这些虚拟地址都是映射到那一块物理内存上,所以这些虚拟地址空间自然要比实际的物理内存大。所以Linux在CPU的内存管理单元MMU中维护了一个内存映射,通过这一块小单元映射就可以把虚拟地址映射为进程的物理地址了(补充:而且Linux在CPU缓存中还维护了一个TLB,用来缓存已经找到的地址映射(页表),加速了对寻找内存映射的访问)。
页面的一部分放在物理内存中,一部分放在磁盘中。当程序访问到了一个页面,它的虚拟地址没有与物理内存映射,就会发生缺页中断:Linux会让进程陷入到内核空间,内核空间通过页面置换算法得到一块空闲的物理内存,然后把磁盘中需要访问的页面读入这块物理内存,然后修改虚拟地址和物理内存的映射关系,然后返回用户空间重新执行指令。
MMU规定了虚拟地址空间的最小单位叫做页,那么这个映射关系表就叫做页表,映射关系就叫做页表项。当页表项越来越多时,就会占用大量空间。所以Linux提供了多级页表和大页。
多级页表就是把内存分区管理,将原来的映射关系改成区索引和区内的偏移(页表中的虚拟页号与索引匹配,然后再通过偏移量就嫩得到物理内存地址)。由于虚拟内存空间通常只用了一小部分,所以多级页表中就只保存这一小部分的区块。
然而对于很多情况,有多个独立的地址空间要比 仅仅是一维的一个接一个的页面好得多。而且一维的连续存储页面是不易具备逻辑功能的。所以我们把虚拟地址空间中的用户空间分为若干有实际意义的段,然后把每个段看做成一个虚拟内存,再把每个段分成若干页面进行存储。而且段的大小可以随着程序的数据结构大小的变化而变化,这样就更加有利于我们虚拟内存的管理。(只读段{代码与常量}、数据段{全部变量}、堆、文件映射段{共享内存等}、栈)
页面置换算法
为什么要页面置换:上面....。发生页面置换时,要检测此页面是否被修改。若未被修改则直接淘汰,若被修改则需要写回磁盘以更新磁盘上的副本。
①最优页面置换算法:发生缺页中断时,置换掉最久不会被访问的页面,不可能实现。
②最近未使用:在页面被访问时更新它的R位、被修改时更新它的M位。然后按照未访问未修改、已访问未修改等 分为编号由小到大的四类。发生缺页中断时,在编号最小的非空类中随机挑选一个页面淘汰。
③先进先出:操作系统维护一个链表,最早进入的页面放在表头。发生缺页中断时,淘汰表头页面。但仅仅使用纯粹的先进先出页面置换算法容易把常用的页面淘汰掉,所以有了第二次机会页面置换算法。
④第二次机会:在淘汰表头页面时,会先检测页面的R位,若它最近被访问过,则把它R位置0并移到表位。它实际就是寻找在一个最近时间间隔内未被访问的页面。
⑤最近最少使用:在发送缺页中断时,置换未被使用时间最长的页面。它通过访问计数器实现,发生缺页中断时就淘汰计数器最小的页面。
【内存寻址相关】:32位系统中,用户空间:内核空间 = 3:1