操作系统之内存管理

内存

内存使用:
	将程序放到内存中,PC指向开始地址,然后取指执行。


地址总线:
  (1)CPU是通过地址总线来指定存储单元的。

  (2)地址总线决定了cpu所能访问的最大内存空间的大小。

  (3)地址总线是地址线数量之和。

内存地址:
	只是一个编号,代表一个内存空间
	内存地址所执行的内存单元大小就是1字节。

寻址空间:
	寻址空间一般指的是CPU对于内存寻址的能力。
	内存空间大小就是寻址能力,即能访问到多少个地址。
	CPU最大能查找多大范围的地址叫做寻址能力,CPU的寻址能力以字节为单位 。
	如32位寻址的CPU可以寻址2的32次方大小的地址也就是4G,这也是为什么32位的CPU最大能搭配4G内存的原因。


物理内存:
	实际内存。

虚拟内存:
	1. 每一个运行的进程,都会获得一块内存地址空间,这就是所谓的虚拟内存。
	2. 这里面的所有地址都是虚拟的,和物理内存并不直接挂钩。
	3. 这些虚拟地址所映射到的实际地址,可以是物理内存地址,也可以是页面文件的地址。
	4. 如果物理内存小于这个虚拟地址的范围,
	   使用的时候可以将内存数据写入页面文件,通过清空内存数据,以提高物理内存的利用效率。


页面文件:
	硬盘上的一块空间,在Windows下表现为一个文件。
	这个页面文件存在的意义就是在物理内存被占用满以后,
	将物理内存中的东西移动到硬盘上,腾出物理内存给需要的应用程序来使用。

内存管理

内存管理和虚拟内存管理:

	内存管理包括:
		程序装入等概念、
		交换技术、
		连续分配管理方式、
		非连续分配管理方式(分页、分段、段页式)。

	虚拟内存管理包括:
		虚拟内存概念、
		请求分页管理方式、
		页面置换算法、页
		面分配策略、
		工作集、
		抖动。

程序装入和链接

编译:
	由编译程序将用户源代码编译成若干个目标模块。


链接:
	由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块。


装入:
	由装入程序将装入模块装入内存运行。

重定位(修改程序中的相对地址):
	1. 编译时重定位的程序只能放在内存固定位置
	2. 载入时重定位(静态重定位装入)的程序一旦载入内存就不能动了
	3. 重定位最合适的时机:运行时重定位(动态重定位装入)
	
动态重定位的特点:
	1. 可以将程序分配到不连续的存储区中。
	2. 在程序运行之前可以只装入它的部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存。
	3. 便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。

内存保护

没有内存抽象(重定位)的弊端:
	1. 程序直接访问和操作的都是物理内存。
	2. 用户程序可以访问任意内存,容易破坏操作系统,造成崩溃
	3. 同时运行多个程序,可以相互访问内存,造成程序崩溃。


内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。

通过 界地址寄存器 和 重定位寄存器 来实现这种保护:

	界地址寄存器含逻辑地址值。

	重定位寄存器含最小的物理地址值。


当CPU调度程序选择进程执行时,派遣程序会初始化 界地址寄存器 和 重定位寄存器。
每一个 逻辑地址 都需要与这两个寄存器进行核对,
如果未发生地址越界,则加上 重定位寄存器 的值后映射成 物理地址,再送交内存单元。
以保证操作系统和其他用户程序及数据不被该进程的运行所影响。

基本的存储分配方式

内存连续分配管理方式(容易产生内存碎片)

连续分配方式,是指为一个用户程序分配一个连续的内存空间。它主要包括:

    1. 单一连续分配(分为系统区和用户区,无需内存保护,进程之间可见)

    2. 固定分区分配(将用户内存空间划分为若干个固定大小的区域,每个分区只装入一道作业,容易产生浪费和不足)

    3. 动态分区分配(不预先将内存划分,而是在进程装入内存时,
            根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要)

内存非连续分配管理方式

允许一个程序分散地装入到不相邻的内存分区中。根据分区的大小是否固定分为:

    1. 分页存储管理方式

    2. 分段存储管理方式

分页(地址结构:页号、位移量(业内地址))(内存)

分区:
	分为固定分区与可变分区,分配内存会产生效率问题(内存碎片)。

引入分页的目的:
	解决内存分区导致的内存效率问题


分页存储的几个概念:

	a. 页面和页面大小。
	   进程(虚拟内存)中的块称为页(Page),
	   内存(物理内存)中的块称为页框(Page Frame,或页帧),
	   外存也以同样的单位进行划分,直接称为块(Block)。
	   进程在执行时需要申请主存空间,就是要为每个页面分配主存中的可用页框,这就产生了页和页框的一一对应。

	b. 地址结构。
	   地址结构包含两部分:前一部分为页号 P,后一部分为页内偏移量 W。
	   地址长度为 32 位,其中 0~11 位为页内地址,即每页大小为 4KB ;12~31 位为页号,地址空间最多允许有 2^20 页。

	c. 页表。
	   为了便于在内存中找到进程的每个页面所对应的物理块,
	   系统为每个进程建立一张页表,记录页面在内存中对应的物理块号,页表一般存放在内存中。
	   页表的作用是实现从页号到物理块号的地址映射。


分页存储管理方式根据运行作业时是否要把作业的所有页面都装入内存才能运行分为:
	1. 基本分页存储管理方式
	2. 请求分页存储管理方式(内存换入换出)


基本分页存储管理方式:

	连续分区会产生外部碎片,对内存的利用率都比较低。

	为了尽量避免碎片的产生,引入了分页的思想:
		把主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位。
		每个进程也以块为单位进行划分,进程在执行时,以块为单位逐个申请主存中的块空间。


分页管理方式存在的两个主要问题:

	1. 每次访存操作都需要进行逻辑地址到物理地址的转换,地址转换过程必须足够快,否则访存速度会降低;

	2. 每个进程引入了页表,用于存储映射机制,页表不能太大,否则内存利用率会降低。


多级页表:

	为了提高内存空间利用率,页应该小。但是页小了,页表就大。

	第一种尝试,只存放用到的页:用到的逻辑页才有页表项
		但页表中的页号不连续,就需要比较、查找,折半,降低cpu效率。

	既要连续又要让页表占用内存少:多级页表
		建立上一级页表,用于存储页表的映射关系。


一级页表的两个问题:

	1.页表在内存分配是必须连续,否则无法查表。

	2.每个进程都必须占用4M,必须全部分配,进程才可以使用。

二级页表的优势:

	1.允许页表被分散在内存的各个页面中,不需要连续的4M内存块;

	2.不需要为未使用部分分配二级页表;

	3.可以在虚拟内存中存放二级页表。


快表:

	若页表全部放在内存中,则存取一个数据或一条指令至少要访问两次内存:
		1. 一次是访问页表,确定所存取的数据或指令的物理地址
		2. 二次才根据该地址存取数据或指令。
		显然,这种方法比通常执行指令的速度慢了一半。

	为此,在地址变换中增设了一个具有并行查找能力的高速缓冲存储器——快表,又称联想寄存器(TLB):
		用来存放当前访问的若干页表项,以加速地址变换的过程。
		与此对应,主存中的页表——慢表。

分页地址变化原理

给出逻辑地址的页号和页内地址,开始进行地址变换:

    1)       在被调进程的PCB中取出页表始址和页表大小,装入页表寄存器

    2)       页号与页表寄存器的页表长度比较,若页号大于等于页表长度,发生地址越界中断,停止调用,否则继续

    3)       由页号结合页表始址求出块号

    4)       块号&页内地址,即得物理地址

分页思想

分页问题

多级分页

分段(地址结构:段号、位移量(段内地址))(段面向用户/页面向硬件)

基本分段存储管理方式:

	分页管理方式是从计算机的角度考虑设计的,以提高内存的利用率,提升计算机的性能。
	且分页通过硬件机制实现,对用户完全透明。
	
	而分段管理方式的提出则是考虑了用户和程序员,以满足方便编程、信息保护和共享、动态增长及动态链接等多方面的需要。


分段:
	段式管理方式按照用户进程中的自然段划分逻辑空间。
	例如,用户进程由主程序、两个子程序、栈、一段数据组成,
	于是可以把这个用户进程划分为5个段,每段从 0 开始编址,
	并分配一段连续的地址空间(段内要求连续,段间不要求连续,因此整个作业的地址空间是二维的)。
	其逻辑地址由段号 S 与段内偏移量 W 两部分组成。


段表:
	每个进程都有一张逻辑空间与内存空间映射的段表,其中每一个段表项对应进程的一个段,
	段表项记录该段在内存中的起始地址和段的长度。


段的共享与保护(写时复制):
	在分段系统中,段的共享是通过两个作业的段表中相应表项指向被共享的段的同一个物理副本来实现的。

	当一个作业正从共享段中读取数据时,必须防止另一个作业修改此共享段中的数据,应此这个共享段是只读的。
	当某个作业需要修改数据时,则需要另外开辟内存空间,将地址指向新开辟的空间。
	不能修改的数据是可以共享的。而可修改的代码和数据则不能共享。


段页式管理方式:
	1. 页式存储管理能有效地提高内存利用率
	2. 分段存储管理能反映程序的逻辑结构并有利于段的共享。

	在段页式系统中,作业的地址空间首先被分成若干个逻辑段,每段都有自己的段号,
	然后再将每一段分成若干个大小固定的页。

	在进行地址变换时,首先通过段表查到页表起始地址,然后通过页表找到页帧号,最后形成物理地址。


段页式系统中,获得一条指令或数据需要访问三次内存:
	1. 访问段表,获得页表始址
	2. 访问页表,获得物理块号
	3. 访问真正的数据

	可以增设一个高速缓存寄存器

分段地址变化原理及步骤

物理地址=基址+段内地址

给出逻辑地址的段号和段内地址,开始进行地址变换:

    1)       在被调进程的PCB中取出段表始址和段表长度,装入控制寄存器

    2)       段号与控制寄存器的页表长度比较,若页号大于等于段表长度,发生地址越界中断,停止调用,否则继续

    3)       由段号结合段表始址求出基址

    4)       基址+段内地址,即得物理地址

段页式系统(地址结构:段号、页号、页内地址)

给出逻辑地址的段号、页号、页内地址,开始进行地址变换:

    1)       在被调进程的PCB中取出段表始址和段表长度,装入段表寄存器

    2)       段号与控制寄存器的页表长度比较,若页号大于等于段表长度,发生地址越界中断,停止调用,否则继续

    3)       由段号结合段表始址求出页表始址和页表大小

    4)       页号与段表的页表大小比较,若页号大于等于页表大小,发生地址越界中断,停止调用,否则继续

    5)       由页表始址结合段内页号求出存储块号

    6)       存储块号&页内地址,即得物理地址

虚拟存储器

基于局部性原理,在程序装入时,可以将程序的一部分装入内存,
而将其余部分留在外存,就可以启动程序执行。

在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。

另一方面,操作系统将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入内存的信息。

这样,系统好像为用户提供了一个比实际内存大得多的存储器,称为虚拟存储器。


虚拟内存的实现有以下三种方式:
	请求分页存储管理。
	请求分段存储管理。
	请求段页式存储管理。

不管哪种方式,都需要有一定的硬件支持。一般需要的支持有以下几个方面:

	一定容量的内存和外存。

	页表机制(或段表机制),作为主要的数据结构。
	
	中断机构,当用户程序要访问的部分尚未调入内存,则产生中断。
		在请求分页系统中,每当所要访问的页面不在内存时,便产生一个缺页中断,请求操作系统将所缺的页调入内存。
		此时应将缺页的进程阻塞(调页完成唤醒)。
		如果内存中有空闲块,则分配一个块,将要调入的页装入该块,并修改页表中相应页表项。
		若此时内存中没有空闲块,则要淘汰某页(若被淘汰页在内存期间被修改过,则要将其写回外存)。

	地址变换机构,逻辑地址到物理地址的变换。

虚拟内存(virtual memory)

将用户逻辑内存和物理内存分开。在物理内存有限的情况下,为程序员提供了巨大的虚拟内存。


当访问虚拟内存时,会通过 MMU(内存管理单元)去匹配对应的物理地址:

	如果虚拟内存的页并不存在于物理内存中,会产生缺页中断,从磁盘中取得缺的页放入内存。

	如果内存已满,还会根据某种算法将内存中的页换出。


页面置换算法:

	在缓存系统中,缓存的大小有限,当有新的缓存到达时,需要淘汰一部分已经存在的缓存,这样才有空间存放新的缓存数据。

	页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。

	1. 先进先出(FIFO, First In First Out)

	2. 改进型FIFO(Second Chance Page Replacement Algorithm)

	3. 时钟替换(Clock Page Replacement Algorithm)

内存换入

原文地址:https://www.cnblogs.com/loveer/p/11688111.html