操作系统 - 进程和内存

操作系统 - 进程和内存

    • 操作系统内核和Shell
    • 系统调用
    • 进程管理
      • 1. 进程控制块PCB
      • 2. 进程的状态
      • 3. 进程通信
        • 3.1 共享存储
        • 3.2 管道 Or 无名管道
        • 3.3 有名管道
        • 3.4 信号
        • 3.5 消息队列
        • 3.6 Socket
        • 3.7 信号量
      • 4. 进程之间的协作关系
        • 4.1 临界资源/区
        • 4.2 进程互斥
        • 4.3 进程同步
        • 4.4 进程通信
        • 4.5 信号量Semaphore、互斥量Mutex、PV原语
        • 4.6 经典问题
          • 4.6.1 生产者消费者问题
          • 4.6.2 读者-写者问题
          • 4.6.3 哲学家进餐问题
      • 5. 进程调度
    • 内存管理
      • 1. 存储管理
        • 1.1 分区管理
        • 1.2 分页管理
          • 1.2.1 CPU寻址 & 虚拟地址 & 物理地址
          • 1.2.2 分页管理
          • 1.2.3 快表(TLB)
          • 1.2.4 多级页表
        • 1.3 分段管理
        • 1.4 段页式管理
      • 2. 虚拟内存
        • 2.1 局部性原理
        • 2.2 虚拟存储器
        • 2.3 虚拟存储技术
        • 2.4 页面置换


操作系统 (Operating System, OS):管理计算机硬件和软件资源的程序,是计算机系统的内核与基石。

操作系统 - 进程和内存_第1张图片

操作系统内核和Shell

操作系统 - 进程和内存_第2张图片

内核 Kernel:

基于硬件的第一层软件的扩充,是硬件与应用程序的桥梁。
功能: 负责管理系统资源(系统进程、内存、设备驱动、文件和网络系统等)。

壳 Shell:

为使用者提供操作界面的软件。
功能: 接收用户命令,调用相应的程序。
类型:

  1. 图形界面shell:Window图形界面、Linux shell
  2. 命令行式shell:cmd.exe、bash/sh/ksh/csh/zsh…

系统调用

由操作系统实现提供的所有系统调用所构成的集合即程序接口或应用编程接口(Application Programming Interface,API)。是应用程序同系统之间的接口。百度百科

想要使用操作系统级别的功能时,需要使用系统调用。

在一般的用户应用程序中,只要需要 核心态 级别的操作(进程控制、内存管理、文件管理、设备管理等等),就必须通过系统调用方式向操作系统提出请求,让操作系统代为完成。

操作系统 - 进程和内存_第3张图片
进程访问资源的特征,进程的运行分为两个等级:
用户态:只可以读取对应用户程序的数据。
核心态:可以读取操作系统所有资源。

几乎所有的应用程序都运行在用户态,如果想要执行核心态级别的功能,就需要用到系统调用。

进程管理

程序:某种程序语言编写的代码集合。
进程:运行的程序,一个动态的过程(产生、存在、结束),存在生命周期。

进程与程序的区别:

  1. 进程是动态的,程序是静态。程序是有序代码的集合;进程是程序的执行,进程会涉及到核心态和用户态的切换。
  2. 进程是暂时的,程序是永久的。进程是一个状态变化的过程,程序可长久保存
    进程是操作系统资源分配的最小单位。
  3. 进程 = 程序 + 数据 + 进程控制块PCB

进程的特点:
动态性:动态的创建、结束;动态的程序;
并发性:可以被独立的调度并占用处理器;
独立性:不同进程工作互不影响;
制约性:共享数据的访问互相制约。

1. 进程控制块PCB

PCB:Process Control Block
PCB用于描述进程的数据结构,操作系统为每一个进程都 维护了一个PCB,用于保存进程相关的状态信息。

组成结构:

进程标识符号:
内部标识符:在所有的操作系统中,都为每一个进程赋予了一个惟一的数字标识符,它通常是一个进程的序号。设置内部标识符主要是为了方便系统使用。
外部标识符:它由创建者提供,通常是由字母、数字组成,往往是由用户(进程)在访问该进程时使用。为了描述进程的家族关系,还应设置父进程标识及子进程标识。此外,还可设置用户标识,以指示拥有该进程的用户。
处理机状态:
主要是由处理机的各种寄存器中的内容组成的。处理机在运行时,许多信息都放在寄存器中。当处理机被中断时,所有这些信息都必须保存在PCB 中,以便在该进程重新执行时,能从断点继续执行。这些寄存器包括:指令计数器、程序状态字、用户栈指针等。
进程调度信息:
进程状态,指明进程的当前状态,作为进程调度和对换时的依据
进程优先级
进程调度所需的其它信息,它们与所采用的进程调度算法有关,比如,进程已等待CPU的时间总和、进程已执行的时间总和等;
事件,指进程由执行状态转变为阻塞状态所发生的事件,即阻塞原因。
进程控制信息:
程序和数据的地址,指进程的程序和数据所在的内存或外存地(首)址,以便再调度到该进程执行时,能从PCB中找到其程序和数据;
进程同步和通信机制,指实现进程同步和进程通信时必需的机制,如消息队列指针、信号量等,它们可能全部或部分地放在PCB 中;
资源清单,即一张列出了除CPU 以外的、进程所需的全部资源及已经分配到该进程的资源的清单;
链接指针,它给出了本进程(PCB)所在队列中的下一个进程的PCB的首地址。

程序控制块 PCB

2. 进程的状态

操作系统 - 进程和内存_第4张图片

  • 运行状态: 当一个进程正在处理机上运行时。
  • 就绪状态: 一个进程获得了除处理机之外的一切所需资源,一旦得到处理机即资源可运行。
  • 等待(阻塞)状态: 一个进程正在等待某一事件而暂停运行。
  • 创建状态: 一个进程正在被创建,还没被转到就绪状态之前的状态。
  • 结束状态: 一个进程正在从系统中消失时的状态。

3. 进程通信

进程通信:指在进程间传输数据(交换信息)。
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)

操作系统 - 进程和内存_第5张图片

什么时候需要进程通信?
不同的进程需要进行信息交互和状态传递时。

进程间通信IPC (InterProcess Communication)
Android进程间通信之八面玲珑

3.1 共享存储

共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

3.2 管道 Or 无名管道

  • 具有亲缘关系的父子进程之间或者兄弟进程之间的通信。
  • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。
  • 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
  • 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
    操作系统 - 进程和内存_第6张图片

管道机制需要提供一下几点的协调能力

  1. 互斥,即当一个进程正在对pipe执行读/写操作时,其它进程必须等待
  2. 同步,当一个进程将一定数量的数据写入,然后就去睡眠等待,直到读进程将数据取走,再去唤醒。读进程与之类似
  3. 确定对方是否存在

3.3 有名管道

匿名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIFO)。
有名管道不同于匿名管道之处在于它提供了一个路径名与之关联,以有名管道的文件形式存在于文件系统中,这样,即使与有名管道的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过有名管道相互通信,因此,通过有名管道不相关的进程也能交换数据。

3.4 信号

信号是软件层次上对中断机制的一种模拟,是一种异步通信方式。

信号可以在用户空间进程和内核之间直接交互,内核可以利用信号来通知用户空间的进程发生了哪些系统事件,信号事件主要有两个来源:

  1. 硬件来源:用户按键输入Ctrl+C退出、硬件异常如无效的存储访问等。
  2. 软件终止:终止进程信号、其他进程调用kill函数、软件异常产生信号。
    操作系统 - 进程和内存_第7张图片

3.5 消息队列

  1. 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。
  2. 与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。
  3. 另外与管道不同的是,消息队列在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。
  1. 消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识;
  2. 消息队列允许一个或多个进程向它写入与读取消息;
  3. 管道和消息队列的通信数据都是先进先出的原则;
  4. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取;比FIFO更有优势;
  5. 消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺;
  6. 目前主要有两种类型的消息队列:POSIX消息队列以及System V消息队列,系统V消息队列目前被大量使用。系统V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除。

3.6 Socket

套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

操作系统 - 进程和内存_第8张图片

3.7 信号量

信号量与管道,FIFO以及消息队列不同。它是一个计数器,用于为多个进程提供共享数据对象的访问,信号量的意图在于进程间同步


4. 进程之间的协作关系

操作系统中的并发进程有些是独立的有些需要相互协作,独立的进程在系统中执行不影响其他进程,也不被其他进程影响(因为他们没有共同需要一起用到的资源)。
而另外一些进程则需要与其他进程共享数据,以完成一项共同的任务。 因此,为了保证操作系统的正常活动,使得程序的执行具有可再现性,保证执行结果的正确性。操作系统必须为这种协作的进程提供某种机制。 进程间的协作关系分为:互斥,同步,通信。

互斥:
多个进程不允许同时使用同一个资源。
同步:
多个进程中事件发生的时间存在某种先后顺序。
通信:
多个进程间要传递一定的信息。

进程同步和互斥

4.1 临界资源/区

在计算机中,某段时间内只允许一个进程使用的资源称为临界资源,比如打印机,共享变量等等。而每个进程访问临界资源的那段程序代码称为临界区。

4.2 进程互斥

互斥亦称间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待, 当占用临界资源的进程退出临界区后,另一进程才允许去访问此临界资源。

例如,在仅有一台打印机的系统中,有两个进程A和进程B,如果进程A需要打印时, 系统已将打印机分配给进程B,则进程A必须阻塞。一旦进程B将打印机释放,系统便将进程A唤醒,并将其由阻塞状态变为就绪状态。

为禁止两个进程同时进入临界区,同步机制应遵循以下准则:

  • 空闲让进:临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区。
  • 忙则等待:当已有进程进入临界区时,其他试图进入临界区的进程必须等待。
  • 有限等待:对请求访问的进程,应保证能在有限时间内进入临界区。
  • 让权等待:当进程不能进入临界区时,应立即释放处理器,防止进程忙等待。

进程互斥的实现方法

4.3 进程同步

同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作。

例如,输入进程A通过单缓冲向进程B提供数据。当该缓冲区空时,进程B不能获得所需数据而阻塞,一旦进程A将数据送入缓冲区,进程B被唤醒。反之,当缓冲区满时,进程A被阻塞,仅当进程B取走缓冲数据时,才唤醒进程A。

进程同步的几种实现方式

4.4 进程通信

见进程管理的第3节。

4.5 信号量Semaphore、互斥量Mutex、PV原语

互斥量:
用于互斥,信号量用于同步。这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
一般来说,互斥量为 0/1变量, 0表示互斥量对应的临界资源被占用, 1表示互斥量对应的临界资源可用。
信号量:
非负整数,用在多线程多任务同步中,一个进程完成了某一个动作就通过信号量告诉别的进程,别的线程再进行某些动作。一般来说 信号量 的值表示资源的数目。
信号量的值与相应资源的使用情况有关。
  1. 当它的值大于0时,表示当前可用资源的数量;2. 当它的值小于0时,其绝对值表示等待使用该资源的进程个数。信号量机制
原语:
由若干个机器指令构成的完成某种特定功能的一段程序,具有 不可分割性(原子性),即原语的执行必须是连续的,在执行过程中不允许被中断。primitive or atomic action。
P原语:申请资源
V原语:释放资源

Notices:mutex 是服务于共享资源的;而semaphore 是服务于多个进程间的执行的逻辑顺序的。
信号量和互斥量的区别

4.6 经典问题

操作系统之经典进程同步问题

4.6.1 生产者消费者问题

问题描述: 生产者-消费者模型描述的是有一群生产者进程在生产产品,并将这些产品提供给消费者进程并发进行,具备并发程序的典型特征。PCM为使生产者进程和消费者进程并发进行,在它们之间设置一个具有多个缓冲区的缓冲池生产者进程可以将其所生产的产品放入一个缓冲区中,消费者进程可以从一个缓冲区中取得产品去消费。尽管所有的生产者进程和消费者进程都是以异步方式运行的,但他们之间必须保持同步,既不允许消费者进程从空的缓冲区中拿产品,也不允许生产者进程向满缓冲区中放产品。

问题分析:

  1. 我们可以利用一个数组来表示上述的具有n个缓冲单元的缓冲区。
  2. 用输入指针in作写指针,每当生产者进程生产并投放一个产品时,in++
  3. 同理,out指针作为读指针,每当消费者拿走一个产品时out++
  4. 由于缓冲区是循环队列,则加1写成,in=(in+1)mod nout同理。当(in+1)mod n==out时,缓冲区满,当in==out时,缓冲区为空。
  5. 此外还引入了count,当生产者生产并放入时加1,消费者拿走时则减1
4.6.2 读者-写者问题

问题描述:一个数据文件或记录可被多个进程所共享,将其中只要求读该文件的进程称为读者,其他进程称为写手。多个读者进程和多个写手进程在某个时间段内对该文件资源进行异步操作。限制如下:

  • 写-写互斥;
  • 读-写互斥;
  • 读-读允许。
	// 设置两个互斥量,
	int wmutex = 1;	 //另一个是写手互斥量(锁)
	int rmutex = 1;  // 一个是读者互斥量(锁),作用是 互斥访问 readcount
	int readcount = 0; // 存储当前进行读操作的读者数目
	void reader() {
		do {
			wait(rmutex); // 一位读者进入(阅读),获取读者互斥量
			if (readcount == 0) { 
			// 这是第一位进行读操作的读者,需要需要加上 写锁(就是说这时候不能写)
				wait(wmutex);		
			}
			readcount++;	// 读者数目增加
			signal(rmutex);	// 释放读者互斥量
			// ======================================
			// 读操作,此时进行的读操作无需互斥
			// ======================================
			wait(rmutex);	// 一位读者完成读操作(阅读),获取读者互斥量
			readcount--;	// 读者数目减少
			if (readcount == 0) {
			// 这是最后一位进行读操作的读者,需要需要释放写锁(就是说这时候可以进行写操作了)
				signal(wmutex);
			}
			signal(rmutex); // 释放读者互斥量
		} while (true);
	}
	void writer() {
		do {
			wait(wmutex);	// 获取写锁
			// ======================================
			// 进行写操作;
			// ======================================
			signal(wmutex); // 释放写锁
		} while (true);
	}

操作系统——读者写者问题

4.6.3 哲学家进餐问题

问题描述:有五位哲学家,它们的生活方式是交替的进行思考和进餐。哲学家门共用一张圆桌,分别坐在周围的五张椅子上。在圆桌上有五只碗和五根筷子,平时哲学家进行思考,饥饿的时候取其左右的靠他最近的筷子,只有当拿到两根筷子时才能进餐。

该方法存在的问题:当哲学家都成功的拿起左边的筷子时都处于“等待”状态,进而发生死锁的问题。

解决方案:

  1. 至多只允许四位哲学系同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用完时释放出他用过的两根筷子。
  2. 当哲学家的左、右两根筷子均可用时,才允许他拿起筷子进餐。
  3. 规定奇数号哲学家先拿起他左边的筷子,然后再去拿他右边的筷子;而偶数号则相反。按此规定,总会有一位哲学家能进餐,并在使用完后释放筷子。

5. 进程调度

大多数系统中,用户进程数一般都多于处理机数、这将导致它们互相争夺处理机。另外,系统进程也同样需要使用处理机。
这就要求进程调度程序按一定的策略,动态地把处理机分配给处于就绪队列中的某一个进程,以使之执行。

FCFS(First Come First Service)
先到先运行。

SJF(Short Job First)
运行时间最短的先处理。

RR(Round Robin)
平均分配时间片,轮着运行。最公平,使用最广。

Priority 优先级调度
分配优先级,高优先级先处理,相同优先级使用FCFS。

多级反馈队列调度:

  1. 设有N个队列(Q1,Q2....QN),其中各个队列对于处理机的优先级是不一样的,也就是说位于各个队列中的作业(进程)的优先级也是不一样的。一般来说,优先级Priority(Q1) > Priority(Q2) > ... > Priority(QN)
  2. 优先级最低的队列遵循RR。
  3. 各个队列的时间片是随着优先级的增加而减少的,也就是说,优先级越高的队列中它的时间片就越短。

操作系统 - 进程和内存_第9张图片
操作系统中的进程调度策略有哪几种



内存管理

操作系统 - 进程和内存_第10张图片

操作系统的内存管理主要负责内存的分配和回收,另外还包括内存地址转换、虚拟存储技术等。

操作系统之内存管理,啃完的人都超神了!!

1. 存储管理

1.1 分区管理

连续内存管理,每次分配连续的一块空间。容易造成内存碎片。

1.2 分页管理

在了解分页之前我们需要了解一下CPU寻址 & 虚拟地址 & 物理地址

1.2.1 CPU寻址 & 虚拟地址 & 物理地址

现代的处理器使用的都是一种叫做虚拟地址寻址(Virtual Addressing) 的寻址方式。

Question 1:为什么需要虚拟地址?

Answer 1:
内存是有限的,但是应用程序的需求可能大于真实内存甚至会有多个应用程序同时运行,这种情况下如何解决?

某台计算机总的内存大小是128M,现在同时运行两个程序ABA需占用内存10MB需占用内存110M
计算机在给程序分配内存时会采取这样的方法:先将内存中的前10M分配给程序A,接着再从内存中剩余的118M中划分出110M分配给程序B。这种分配方法可以保证程序A和程序B都能运行,但是这种简单的内存分配策略(分区管理)问题很多,大致如下:

  1. 进程的地址空间不隔离。

由于程序都是直接访问物理内存,所以恶意程序可以随意修改别的进程的内存数据,以达到破坏的目的。有些非恶意的,但是有bug的程序也可能不小心修改了其它程序的内存数据,就会导致其它程序的运行出现异常。这种情况对用户来说是无法容忍的,因为用户希望使用计算机的时候,其中一个任务失败了,至少不能影响其它的任务。

  1. 内存使用效率低。

在A和B都运行的情况下,如果用户又运行了程序C,而程序C需要20M大小的内存才能运行,而此时系统只剩下8M的空间可供使用,所以此时系统必须在已运行的程序中选择一个将该程序的数据暂时拷贝到硬盘上,释放出部分空间来供程序C使用,然后再将程序C的数据全部装入内存中运行。可以想象得到,在这个过程中,有大量的数据在装入装出,导致效率十分低下。

  1. 程序运行的地址不确定。

当内存中的剩余空间可以满足程序C的要求后,操作系统会在剩余空间中随机分配一段连续的20M大小的空间给程序C使用,因为是随机分配的,所以程序运行的地址是不确定的。但是我们的某些硬件是需要在固定的地址上去开始运行的,但是如果这个地址后边被我们的程序占有,那么我们对这块内存的修改,就可能导致某些硬件不可用了。

  1. 内存碎片多

连续内存管理,每次分配连续的一块空间。容易造成内存碎片。

总结的说:直接使用物理地址。可能对操作系统造成伤害并且难以同时运行多个程序。

为了解决以上问题,大牛们提出使用一个中间层,通过间接方式访问物理内存;这种方式中,程序中访问的内存地址不再是实际的物理内存地址,而是一个虚拟地址,然后由操作系统将这个虚拟地址映射到适当的物理内存地址上。

这样,只要OS处理好虚拟地址到物理内存地址的映射,就可以保证不同的程序最终访问的内存地址位于不同的区域,彼此没有重叠,就可以达到内存地址空间隔离的效果。

Question 2: 如何进行地址的映射?
物理地址: 物理地址空间是实在的存在于计算机中的一个实体,在每一台计算机中保持唯一独立性。我们可以称它为物理内存;如在32位的机器上,物理空间的大小理论上可以达到 2 32 2^{32} 232字节(4GB),但如果实际装了512M的内存,那么其物理地址真正的有效部分只有512MB = 512 * 1024 KB = 512 * 1024 * 1024 B(0x00000000~0x1fffffff)

虚拟地址: 虚拟地址并不真实存在于计算机中。每个进程都分配有自己的虚拟空间,而且只能访问自己被分配使用的空间。
理论上,虚拟空间受物理内存大小的限制,如给有4GB内存,那么虚拟地址空间的地址范围就应该是0x00000000~0xFFFFFFFF每个进程都有自己独立的虚拟地址空间。 这样每个进程都能访问自己的地址空间,这样做到了有效的隔离。

我们平时操作的内存其实都是通过操作虚拟地址的内存单元。通过通过MMU(Memory Manage Unit) 的映射来间接的操作我们的物理地址。
操作系统 - 进程和内存_第11张图片

虚拟地址 和 物理地址

1.2.2 分页管理

物理上将内存分为不同的页。提高内存利用率,减少了碎片。
通过页表对应逻辑地址和物理地址
操作系统 - 进程和内存_第12张图片

分页:将段分成均匀的小块,通过页表映射物理内存。

分页内存管理的两个问题:

  1. 地址转换要快(虚拟地址–>物理地址);
  2. 页表可能非常大;

操作系统解决这两个问题分别提出了快表多级页表的概念。

1.2.3 快表(TLB)

为了提高虚拟地址到物理地址的转换速度。页表的基础上增加快表。
引入快表之后地址转换流程:

  1. 虚拟地址中页号 PageNum
  2. PageNum在快表中,直接从快表中读取物理地址;
  3. PageNum不在快表中,则去访问页表并从页表中访问物理地址,并将此次的逻辑地址->物理地址 的映射增加到快表中;
  4. 快表满了又需要增加新的页,使用淘汰策略淘汰掉快表中的页。

快表对于页表:就像Redis对于DB,高速缓存对于内存。

1.2.4 多级页表

对于页表可能非常大的问题,这是由于现代计算机使用的虚拟地址至少是32位。

比如,当页面大小为4KB时,32位的地址空间将有 2 20 2^{20} 220页面,64位的地址空间则更多。
2 20 2^{20} 220个页表项都得放在内存中,需要4M内存;并且请记住,每个进程都需要有自己的页表(因为每个进程有自己的虚拟地址空间)。

实际上,大部分页表中大部分逻辑地址根本不会用到。

所以提出多级页表的概念;其中,一级页表可以看做是页表的目录。
只有一级页表才需要总是在主存中;二级页表在在需要时创建,这就减少了主存的压力;并且只有最经常使用的二级页表才需要缓存在主存中,这种离散的存储方式是非常便利的。

多级页表是为了节省空间。使得页表可以在内存中离散存储。

操作系统 - 进程和内存_第13张图片

虚拟内存,页表,快表,多级页表
操作系统-多级页表与快表

1.3 分段管理

逻辑上进行段的划分,是根据用户的需要划分,段对用户是可见的。

将程序分为代码段、数据段、堆栈段等;

1.4 段页式管理

  1. 先将内存分为多个段;
  2. 每个段又被分为多个页;

分段:将程序分为代码段、数据段、堆栈段等; 分页:将段分成均匀的小块,通过页表映射物理内存;

操作系统之内存管理

2. 虚拟内存

虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。

  • 维基百科

Question 1: 存在这样一种情况:我们平时运行的程序所占用的内存可能远大于物理内存,这种情况OS是如何进行处理的?

Answer 1: 虚拟内存让每个进程认为自己拥有连续的、私有的一块内存空间。

当一个进程试图访问虚拟地址空间中的某个数据时,会经历下面两种情况的过程:

  1. CPU想访问某个虚拟内存地址,找到进程对应的页表中的条目,判断有效位, 如果有效位为1,说明在页表条目中的物理内存地址不为空,根据物理内存地址,访问物理内存中的内容,返回。
  2. CPU想访问某个虚拟内存地址,找到进程对应的页表中的条目,判断有效位,如果有效位为0,但页表条目中还有地址,这个地址是磁盘空间的地址,这时触发缺页异常,系统把物理内存中的一些数据拷贝到磁盘上,腾出所需的空间,并且更新页表。此时重新执行访问之前虚拟内存的指令,就会发现变成了情况1。

如何理解虚拟内存

2.1 局部性原理

时间局部性:刚刚运行的指令,在以后更有可能被运行。

典型原因:程序中存在很多循环操作。

空间局部性:刚刚访问的存储单元,在之后访问的可能性更大。

典型原因:指令的顺序存放,数据通过数组、向量、表等形式。

时间局部性是通过将近来使用的指令和数据保存到高速缓存存储器中,并使用高速缓存的层次结构实现。
空间局部性通常是使用较大的高速缓存,并将预取机制集成到高速缓存控制逻辑中实现。
虚拟内存技术实际上就是建立了“内存一外存"的两级存储器的结构,利用局部性原理实现高速缓存。

操作系统 - 进程和内存_第14张图片

局部性原理是缓存设计的重要理论基础。

2.2 虚拟存储器

基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其他部分留在外存,就可以启动程序执行。由于外存往往比内存大很多,所以我们运行的软件的内存大小实际上是可以比计算机系统实际的内存大小大的。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换到外存上,从而腾出空间存放将要调入内存的信息。这样,计算机好像为用户提供了一个比实际内存大的多的存储器–虚拟存储器
操作系统 - 进程和内存_第15张图片

实际上,我觉得由于内存成本高,所以基于时间换空间策略提出虚拟内存,使用时间(页的调入调出),换来了一个虚拟的更大的空间来支持程序的运行。
时空互换的思想!

2.3 虚拟存储技术

在分页、分段、段页式的基础上进行实现;增加请求调页 / 调段、置换功能。

  1. 请求分页管理
  2. 请求分段管理
  3. 请求段页式管理

三种方式共同点:

  1. 一定容量的内存和外存,程序部分在内存,部分在外存(需要时加载);
  2. 缺页中断:需要执行的指令或访问数据尚未在主存中(称为缺页和缺段),则需要从外存中调入。
  3. 虚拟地址空间:逻辑地址到物理地址的变换。

分页、请求分页的区别:
请求分页管理 是 基于分页管理而建立,根本区别是:是否完全将程序所需地址都装入主存中。分页管理:全部加载到主存,请求分页管理:提供虚拟存储。

2.4 页面置换

需要的页不在内存中的时候,会出现缺页中断。这种情况下需要进行页面的置换。

  1. 存在空闲页面,直接引入需要的页面;
  2. 不存在空闲页面,则需要淘汰一些页面然后再引入需要的页面。

由于第二种情况,所以需要权衡淘汰哪些页面,我们将权衡淘汰哪些页面的算法称为:页面置换算法

  1. FIFO(First In First Out) 页面置换算法:

总是淘汰最先进入内存的页面,即选择在内存中驻留时间最长的页面。

  1. LRU(Least Currently Used) 最久未使用页面置换:

LRU算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间T,当须淘汰一个页面时,选择现有页面中其T值最大的,即最久未使用的页面予以淘汰

  1. LFU(Least Frequently Used) 最少未使用页面置换:

选择最少使用的页面作为淘汰页。

  1. OPT页面置换算法(最佳页面置换算法):

选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。一般作为衡量其他置换算法的方法。

简而言之,可用的置换方法的主要思想如下:
  1. 呆在内存中最久的;
  2. 最久未使用的;
  3. 使用最少的。

你可能感兴趣的:(计算机基础,操作系统,进程管理,内存管理)