Linux:程序地址空间及常见页面置换算法

研究背景以及定义

环境:32为平台

在了解程序地址空间之前我们需要知道:

地址:内存地址------对内存以字节为存储单元的一个编号;通过地址就能找到具体对应的内存单元

程序:其实就是一堆代码,保存在文件(磁盘)中

计算机物理内存的大小是固定的,也就是说计算机主板内存槽上的实际物理内存,cpu可以直接进行寻址,物理内存的容量是固定的,但是寻址的空间取决于cpu地址线的数量。在32位系统上,线性地址空间可达4G(2^32);这4G一般是按照3:1的比例进行分配,用户进程享有3G的空间,而内核独自享有剩下的1G内存
在这里插入图片描述

虚拟内存

编译器在编译程序生成可执行文件时,就会对每一条指令,每一个数据进行一个地址排号,当程序运行时,就会将指令以及数据放到指定的内存地址位置
cpu就会根据地址偏移逐步区执行命令,以及找到对应的数据进行处理
(注意:程序运行之后才会占据内存——因此程序地址空间通常又被成为—进程地址空间)
进程地址空间:实际上也是一个虚拟地址空间,是操作系统作为进程通过一个mm_struct结构体所描述的一个假的地址空间
那么为什么操作系统不让进程直接访问物理内存,而是虚拟内存地址呢?若进程直接访问物理内存有什么不好呢?

1.在程序编译时,编译器就会给指令和数据进行地址编址;但是如果某个地址内存已经被占用,则这个程序就运行不起来了----编译器的地址管理麻烦
2.进程直接访问物理内存,如果有一个野指针,你在操作的时候可能就会把其他进程中的数据改变了(无法进行内存访问控制)
3.程序运行加载通常需要使用一块连续的内存空间,对内存的利用率比较低
注意:虚拟地址不具备存储能力,数据的存储仍然还是要放到内存中

操作系统中管理内存的三种方法:

1.分段式

定义:将用户程序的地址空间分为若干个固定大小的不同的段,在存储分配时,以段为单位,实现了离散分配。
将虚拟地址的组织分为段号+段内偏移量(比如全局数据段有很多变量,他们的段号都是一样的,也就意味着物理内存段的起始变量的偏移量不同)因此,通过段号对应的物理内存段起始地址,以及虚拟地址中地址的偏移量组成一个完整的物理地址,找到对应的物理内存单元
映射逻辑:解析出段号,通过段号在段表中找到对应的段表项,取出段表中的物理地址,与段内偏移进行相加
在这里插入图片描述

优点:可以分别编写和编译,可以针对不同类型的段采取不同的保护,可以按段为单位来进行共享,包括通过动态链接进行代码共享。对编译器的地址管理比较友好
缺点:会产生碎片,没有解决数据连续存储内存利用率低的问题

2.分页式

定义:将用户程序的地址空间分为若干个固定大小的区域,称为“页”或“页面”。也将用户程序的任一页放入任一物理块中,实现了离散分配。
页表如何通过虚拟地址找到物理地址
页表:页号,物理地址,缺页中断位……
虚拟地址的组成:页号+页内偏移
映射逻辑:拿到虚拟地址,解析出页号,通过页号在页表中找到对应的页表项,取出页表项中的物理地址,与页内偏移进行相加
在这里插入图片描述
优点:(1).分页系统不会产生外部碎片,一个进程占用的内存空间可以不是连续的,并且一个进程的虚拟页面在不需要的时候可以放在磁盘中。
(2)分页系统可以共享小的地址,即页面共享。只需要在对应给定页面的页表项里做一个相关的记录即可
缺点:页面很大,会占用大量内存空间

3.段页式

就是分段式与分页式的结合,首先对虚拟地址空间进行分段式管理,然后在每个分段内进行分页管理。是实际的内存管理方式。

缺页中段

定义:指通过虚拟地址找到页表项之后,如果当前地址本来存放的数据不再内存中,就会触发该现象
那么为什么一个数据会不再内存中呢?
这是因为当物理内存不够用的时候,操作系统会根据一定的算法,找出一块物理内存,将其中的数据放到磁盘的交换区中进行存储,当触发缺页中断的时候,这块内存中的原有数据会被重新置换回来。

解决方法——页面置换算法

首先我们需要明确:页面置换时挑选页面的目标主要在于降低随后发生缺页中断的次数或概率。所以,挑选的页面应当是随后相当长时间内不会被访问的页面,最好是再也不会被访问的页面。如果可能,最好选择一个没有修改过的页面,这样替换时就无须将被替换页面的内容写回磁盘,从而进一步加快缺页中断的响应速度。下面给大家介绍几种页面置换算法。

1.最佳(Optimal)置换算法

该算法是由Belasy于1966年题出的一种理论上的算法。该算法的思想是从已经在内存中的页面中选择未来最长时间内不会使用的页面将其置换出去;但是在显示中是无法预测的。这种算法的性能是最好的,因为它对未来的判断达到了100%,因此也决定了它无法实际使用,唯一的作用是作为衡量其他算法的尺度。

2.先进先出(FIFO)页面置换算法

FIFO算法是最早出现的置换算法,该算法的核心思想是总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。这种算法实现简单,只需要把一个进程调入内存的页面按先后次序链接成一个队列,并设置一个指针,称为替换指针。让它总是指向最老的页面。
在这里插入图片描述
缺点:该算法与进程实际运行的规律不相适应,因为在进程中,有些页面经常被访问,比如含有全局变量、常用函数、例程等的页面,FIFO算法并不能保证这些页面不被淘汰

3.LRU(Least Recently Used)置换算法

最近最久未使用(LRU)的页面置换算法是根据页面调入内存后的使用情况做出决策的。核心思想是选择最近最长时间未访问过的页面予以淘汰,它认为过去一段时间内未访问过的页面,在最近的将来可能也不会被访问。该算法为每个页面设置一个访问字段,来记录页面自上次被访问以来所经历的时间,淘汰页面时选择现有页面中值最大的予以淘汰。

4.最少使用(Least Frequently Used,LFU)置换算法

LFU算法和最近最久未使用算法思路相同,都是使用最近的过去预测最近的未来;在该算法里,采取的依据是最近一段时间里的使用次数,选择在最近时期使用最少的页面作为置换页。在采用LFU算法时,应为在内存中的每个页面设置一个移位寄存器,用来记录该页面被访问的频率(访问次数)

5.简单的Clock置换算法—最近未使用(NRU)算法

简单的CLOCK算法是给每一页设置一个访问位,又称使用位。再将内存中的所有页面都通过链接指针链接成一个循环队列。当某一页首次装入主存时,该帧的访问位设置为1;当该页随后再被访问到时,访问位也被置为1。
对于页面替换,该算法中将页面组织为循环队列,每个页面有一个访问位,如果访问过该页面,就将其访问位置为1,否则将其访问位置为0;当寻找置换出去的页面时,遇到第一个访问位为0的页面就将其置换出去,如果遇到访问位为1的页面,依然将其访问位置为1,然后继续寻找;
在这里插入图片描述

由于该算法循环检查各个页面的使用情况,所以叫做Clock算法;

猜你喜欢

转载自blog.csdn.net/qq_43825377/article/details/113803966