操作系统内存管理

内存管理主要负责:

  1. 分配内存(malloc 函数:申请内存)
  2. 回收内存(free 函数:释放内存)

也负责:地址转换->将逻辑地址转换成相应的物理地址等功能(cpu中的MMU负责)。

注:

  1. 编程一般只有可能和逻辑地址打交道,比如在 C 语言中,指针里面存储的数值就可以理解成为内存里的一个地址,这个地址也就是我们说的逻辑地址,逻辑地址由操作系统决定
  2. 物理地址指的是真实物理内存中地址,更具体一点来说就是内存地址寄存器中的地址。物理地址是内存单元真正的地址

局部性原理

早在 1968 年的时候,就有人指出我们的程序在执行的时候往往呈现局部性规律,也就是说在某个较短的时间段内,程序执行局限于某一小部分,程序访问的存储空间也局限于某个区域。

局部性原理表现在以下两个方面:

  1. 时间局部性 :如果程序中的某条指令一旦执行,不久以后该指令可能再次执行;如果某数据被访问过,不久以后该数据可能再次被访问。产生时间局部性的典型原因,是由于在程序中存在着大量的循环操作。
  2. 空间局部性 :一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,这是因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、数组、表等形式簇聚存储的。

时间局部性是通过将近来使用的指令和数据保存到高速缓存存储器中,并使用高速缓存的层次结构实现。

空间局部性通常是使用较大的高速缓存,并将预取机制集成到高速缓存控制逻辑中实现。

内存管理机制

  1. 连续分配管理方式:是指为一个用户程序分配一个连续的内存空间,常见的如 块式管理
  2. 非连续分配管理方式:允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如页式管理段式管理

    1. 块式管理 : 远古时代的计算机操系统的内存管理方式。将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,我们称之为内存碎片
    2. 页式管理 :把主存分为大小相等且固定的一页一页的形式,页较小,相对相比于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。
    3. 段式管理 : 页式管理虽然提高了内存利用率,但是页式管理其中的页实际并无任何实际意义。 段式管理把主存分为一段段的,每一段的空间又要比一页的空间小很多,划分力度更大 。但是,最重要的是段是有实际意义的,每个段定义了一组逻辑信息,例如,有主程序段 MAIN、子程序段 X、数据段 D 及栈段 S 等。 段式管理通过段表对应逻辑地址和物理地址。
    4. 段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段每个段又分成若干页,也就是说 段页式管理机制中段与段之间以及段的内部的都是离散的。

页式管理:快表和多级页表

页式管理(分页管理)需要解决两个核心问题:

  1. 虚拟地址到物理地址的转换速度

  2. 虚拟地址空间大,页表也会很大(页表膨胀)的问题。

快表(TLB)

为了解决虚拟地址到物理地址的转换速度,操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换

我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。

作为页表的 Cache局部性原理),它的作用与页表相似,但是提高了访问速率。

  1. 由于采用页表做地址转换,读写内存数据时 CPU 要访问两次主存(读一次,写一次)。
  2. 有了快表,有时只要访问一次高速缓冲存储器(读),一次主存(写),这样可加速查找并提高指令执行速度。

使用快表之后的地址转换流程是这样的:

  1. 根据虚拟地址中的页号查快表;
  2. 如果该页在快表中,直接从快表中读取相应的物理地址;
  3. 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
  4. 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。

看完了之后你会发现快表和我们平时经常在我们开发的系统使用的缓存(比如 Redis)很像,的确是这样的,操作系统中的很多思想、很多经典的算法,你都可以在我们日常开发使用的各种工具或者框架中找到它们的影子。

多级页表

引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。多级页表属于时间换空间的典型场景,具体可以查看下面这篇文章

多级页表如何节约内存:https://www.polarxiong.com/archives/多级页表如何节约内存.html

页式管理和段式管理的同异

共同点 :

  1. 分页机制和分段机制都是为了提高内存利用率,较少内存碎片。
  2. 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。

区别 :

  1. 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
  2. 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。

虚拟内存

逻辑地址又叫虚拟地址,每个进程都有自己的虚拟地址空间

一个虚拟地址,大小4个字节(32bit),包含着找到物理地址的信息,分为3个部分:

  1. 第22位到第31位这10位(高10位)是页目录中的索引(哪一个数据页),
  2. 第12位到第21位这10位(中10位)是页表中的索引(该索引对应的地址为物理地址基址),
  3. 第0位到第11位这12位(低12位)是页内偏移(上一步的基址加偏移得到真正的物理地址)。

该概念和下面要讲的东西有矛盾,暂时原因不解。

没有虚拟地址空间的时候,程序都是直接访问和操作的都是物理内存:

  1. 用户程序可以访问任意内存,寻址内存的每个字节,这样就很容易(有意或者无意)破坏操作系统,造成操作系统崩溃。
  2. 程序编写困难。想要同时运行多个程序特别困难,比如你想同时运行一个微信和一个 QQ 音乐都不行。为什么呢?举个简单的例子:微信在运行的时候给内存地址 1xxx 赋值后,QQ 音乐也同样给内存地址 1xxx 赋值,那么 QQ 音乐对内存的赋值就会覆盖微信之前所赋的值,这就造成了微信这个程序就会崩溃。

通过虚拟地址访问内存有以下优势:

  1. 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
  2. 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为 4 KB,即8个扇区)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动(局部性原理)。
  3. 不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。

虚拟内存的重要意义是它定义了一个连续的虚拟地址空间,并且 把内存扩展到硬盘空间,

使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,

  1. 它通常是被分隔成多个物理内存碎片,
  2. 还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换(局部性原理)。

与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如 RAM)的使用也更有效率。目前,大多数操作系统都使用了虚拟内存,如 Windows 家族的“虚拟内存”;Linux 的“交换空间”等。From:https://zh.wikipedia.org/wiki/虚拟内存

注: 局部性原理是虚拟内存技术的基础,正是因为程序运行具有局部性原理,才可以只装入部分程序到内存就开始运行。

虚拟内存技术实际上就是建立了 “内存一外存”的两级存储器的结构,利用局部性原理实现高速缓存。

虚拟内存的技术实现

虚拟内存的实现有以下三种方式:

  1. 请求分页存储管理 :建立在分页管理之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。请求分页存储管理系统中,在作业开始运行之前,仅装入当前要执行的部分段即可运行。假如在作业运行的过程中发现要访问的页面不在内存,则由处理器通知操作系统按照对应的页面置换算法将相应的页面调入到主存,同时操作系统也可以将暂时不用的页面置换到外存中。
  2. 请求分段存储管理 :建立在分段存储管理之上,增加了请求调段功能、分段置换功能。请求分段储存管理方式就如同请求分页储存管理方式一样,在作业开始运行之前,仅装入当前要执行的部分段即可运行;在执行过程中,可使用请求调入中断动态装入要访问但又不在内存的程序段;当内存空间已满,而又需要装入新的段时,根据置换功能适当调出某个段,以便腾出空间而装入新的段。
  3. 请求段页式存储管理

请求分页管理和分页管理的根本区别是:

  • 分页管理:将程序全部所需的全部地址空间都装入主存,无法提供虚拟内存
  • 请求分页管理:不要求将作业全部地址空间同时装入主存。可以提供虚存

“请求式管理”都需要:

  1. 一定容量的内存和外存:在载入程序的时候,只需要将程序的一部分装入内存,而将其他部分留在外存,然后程序就可以执行了;
  2. 缺页中断:地址映射过程中(查看页表),若在页面中发现所要访问的页面不在内存中,则发生缺页中断 。,则由处理器通知操作系统将相应的页面或段调入到内存(请求调页),然后继续执行程序,这个时候,被内存映射的磁盘上的文件实际上成了一个分页交换文件
  3. 虚拟地址空间 :逻辑地址到物理地址的变换。

当发生缺页中断时,如果当前内存中并没有空闲的页面,操作系统就必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。用来选择淘汰哪一页的规则叫做页面置换算法,我们可以把页面置换算法看成是淘汰页面的规则。

  1. OPT 页面置换算法(最佳页面置换算法) :最佳(Optimal, OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。一般作为衡量其他置换算法的方法。
  2. FIFO(First In First Out) 页面置换算法(先进先出页面置换算法) : 总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
  3. LRU (Least Recently Used)页面置换算法(最近最久未使用页面置换算法) :LRU算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 T,当须淘汰一个页面时,选择现有页面中其 T 值最大的,即最近最久未使用的页面予以淘汰。【最近在用的保留下来】
  4. LFU (Least Frequently Used)页面置换算法(最少使用页面置换算法) : 该置换算法选择在之前时期使用最少的页面作为淘汰页。【用的最多的保留下来】
Copyright © qgao 2021-* all right reserved,powered by Gitbook该文件修订时间: 2022-06-06 16:56:43

results matching ""

    No results matching ""