操作系统(中)

内存管理

1.什么是虚拟内存?

  • 虚拟内存是一种内存分配方案,是一项可以用来辅助内存分配的机制。
  • 因为每一个进程同时运行,怎么能保证每一进程访问的不是相同的物理内存呢?
    • 让每一个进程都有自己的虚拟内存,进程持有的虚拟地址会通过 CPU 芯⽚中的内存管理单元(MMU)的映射关系, 来转换变成物理地址,然后再通过物理地址访问内存。
2.操作系统是如何管理虚拟地址与物理地址之间的关系?
  • 内存分段:段选择因子+段内偏移量。每一个进程分配一段内存。

 

 

    • 问题:内存碎片
    • 解决方法:内存交换:就是把应用先放入硬盘中,再重新读取到内存,把中间空余的位置补全。比如把音乐放入硬盘中,重新读取,重新读取的时候就紧紧跟着那已经被占⽤了的 512MB 内存后⾯,这样就能空缺出连 续的 256MB 空间,于是新的 200MB 程序就可以装载进来。
    • 新问题:内存交换效率低的问题?内存交换需要频繁和硬盘交互,效率低。如果内存交换的时候,交换的是⼀个占内存空间很⼤的程序,这样整个机器都会显得卡顿。
    • 解决方法:内存分页
  • 内存分页(固定大小的页):页号+页内偏移量。将虚拟内存和物理内存切成一个个固定尺寸的大小,通过一个中间值"页表"来对应,每一个页表有固定数量的"页表项"。 每一个进程对应一个页表,所以每一个页表都是"固定的"大小,linux占4kb。可以说每一个进程都有大小相同的页。

 

    • 换出:如果内存空间不足,通过特定的算法(后面说)会把一些页暂时写在硬盘上。换入:一旦需要的时候再加载进来。
    • 内存分页的换入换出的单位是页,进程空间不够时加载进来几页就行。就增加了内存交换的效率。
    • 问题:有的进程不需要这么大的页,但是每个进程的页大小是相同的,所以就造成了很大的页的浪费,
    • 解决方法:多级页表

 

  •  多级页表(灵活变化大小的页):比如将100万个页表项分为1024个,每一个页表项也是一个页表,也有1024个页表项。
    • 这样做的好处是:如果某个⼀级页表的页表项没有被用到,也就不需要创建这个页表项对应的⼆级页表了,即可以在需要时才创建二级页表。 动态的扩增页的大小

 

    • 多级页表使得虚拟地址到物理地址的转换就多了几道转换的工序,带来了时间上的开销。所以使用一个TLB缓存来存储经常访问的页表项映射。 这个TLB放在CPU芯片中。

 

  •  段页式内存管理:将内存分段与内存分页结合使用。先按照不同的进程分段,然后再分页。 比如Linux采用的就是内存分页,但是不可避免的也使用了分段的管理。   

 

3.物理地址、逻辑地址、有效地址、线性地址、虚拟地址的区别

 

 

 

  • 物理地址:内存中真正的地址,最后被映射的地址。
  • 逻辑地址/有效地址:段内偏移量地址。
  • 线性地址/虚拟地址:每一个进程有一份,需要通过页表映射到物理地址。

 

进程管理 

 1.进程

  • 进程运行中的程序,比如qq音乐,浏览器,微信都是一个个进程。
  • 什么是进程表?
    • 操作系统为了跟踪每个进程的活动状态,维护了一个进程表。在进程表的内部,列出了每个进程的状态以及每个进程使用的资源等。
  • 进程的状态:5种

 

 

    • 补充一个状态:"挂起":描述进程没有占用实际的物理内存空间的情况。比如换出的时候,就属于挂起。
  • 进程的控制结构:在操作系统中,是用进程控制块(process control block,PCB)数据结构来描述进程的,PCB 是进程存在的唯⼀标识。
    • 进程是由内核管理和调度的,所以PCB是在内核中代表一个进程。
    • PCB通常是通过链表的方式进行组织,把具有相同状态的进程链在⼀起,组成各种队列。
    • 比如:将所有处于就绪状态的进程链在⼀起,称为就绪队列; 把所有因等待某事件而处于等待状态的进程链在⼀起就组成各种阻塞队列;

 2.线程

  • 线程:程序的一条执行路径
  • 线程是调度的基本单位,而进程则是资源拥有的基本单位
  • 线程的实现:
    • 用户线程(User Thread):在用户空间实现的线程,不是由内核管理的线程,是由用户态的线程库来完成线程的管理;
    • 内核线程(Kernel Thread):在内核中实现的线程,是由内核管理的线程;
    • 轻量级进程(LightWeight Process):在内核中来支持用户线程;
      • 用户线程与内核线程的对应关系:1对1 ;1 对多;多对多

3.CPU上下文切换

  • 上下文是谁(切换的是谁):CPU寄存器和程序计数器 。我们知道,CPU运行任何一个程序,这两个是必备的环境(不懂CPU运行过程看我的"操作系统(上)")。
  • 就相当于,运行不同的程序,就需要提前准备好自己的环境,供CPU使用。
  • 不同的环境,就需要不同的内核资源,用户资源,线程资源的"保存和恢复"。
    • 内核资源:内核堆栈
    • 用户资源:虚拟内存,全局变量
    • 线程资源:私有数据
  • CPU的上下文切换还分为不同的场景:
    • 进程上下文切换:进程是由内核来管理和调度的,进程的切换只能发生在内核态。 所以,进程的上下文不仅包括了用户资源,还有内核资源
    • 线程上下文切换:线程是调度的基本单位,而进程则是资源拥有的基本单位
      • 不同进程下的线程:就跟进程切换一样
      • 同一进程下的线程:因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程资源就行。
    • 中断上下文切换:为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件
      • 中断上下文切换并不涉及到进程的用户态,只需要切换内核资源

4.进程终止的方式:

  • 正常退出(自愿的):多数进程是由于完成了工作而终止,退出软件。

  • 错误退出(自愿的):比如用户操作了一个不存在的文件,于是编译器就会发出声明并退出

  • 严重错误(非自愿的):由于程序中的错误所导致的。例如,执行了一条非法指令,引用不存在的内存,或者除数是 0 等

  • 被其他进程杀死(非自愿的):某个进程执行系统调用告诉操作系统杀死某个进程。在 UNIX 中,这个系统调用是 kill。在 Win32 中对应的函数是 TerminateProcess

5.进程间的通信方式

  • 管道:其实就是一个进程将数据写到内核中,另一个线程从内核中读取数据。
    • 单向;无格式的流并且大小受限;先进先出;管道这种通信方式效率低,不适合进程间频繁地交换数据;
    • 匿名管道:匿名管道是只能用于存在父子关系的进程间通信
    • 命名管道:可以在任何的进程之间使用,因为使用命名管道的前提,需要在文件系统 创建⼀个类型为 p 的设备文件,那么毫无关系的进程就可以通过这个设备文件进行通信
  • 消息队列:消息队列实际上是保存在内核的「消息链表
    • 缺点:消息队列通信的速度不是最及时的,毕竟每次数据的写入和读取都需要经过用户态与内核态之间的拷贝过程,造成了消耗。
  • 共享内存:它直接分配⼀个共享空 间,每个进程都可以直接访问。可以解决消息队列通信中⽤户态与内核态之间数据拷贝过程带来的开销。
    • 缺点:多进程竞争同个共享资源会造成数据的错乱。
  • 信号量:来保护共享资源,以确保任何时刻只能有⼀个进程访问共享资源,这种方式就是互斥访问。信号量不仅可以实现访问的互斥性,还可以实现进程间的同步,信号量其实是⼀个计数器,表示的是资源个数,其值可以通过两个原⼦操作来控制,分别是 P 操作和 V 操作。
  • 信号:是进程间通信机制中唯 ⼀的异步通信机制,信号可以在应⽤进程和内核之间直接交互,内核也可以利用信号来通知用户空间的进 程发生了哪些系统事件。
    • 信号事件的来源主要有硬件来源(如键盘 Cltr+C )和软件来源(如 kill 命令)
    • ⼀旦有信号发生,进程有三种方式响应信号 1. 执行默认操作、2. 捕捉信号、3. 忽略信号。
    • 有两个信号是应用进程无法捕捉和忽略的,即 SIGKILL 和 SEGSTOP ,这是为了方便我们能在任何时候结束或止某个进程。
  • Socket:要想跨网络与不同主机上的进程之间通信,就需要 Socket 通信了
6.影响调度程序的指标是什么
  • CPU 利⽤率:调度程序应确保 CPU 是始终匆忙的状态,这可提高 CPU 的利⽤率;
  • 系统吞吐量:吞吐量表示的是单位时间内 CPU 完成进程的数量,长作业的进程会占用较长的 CPU 资 源,因此会降低吞吐量,相反,短作业的进程会提升系统吞吐量;
  • 周转时间:周转时间是进程运行和阻塞时间总和,⼀个进程的周转时间越小越好;
  • 等待时间:这个等待时间不是阻塞状态的时间,而是进程处于就绪队列的时间,等待的时间越长,用户越不满意;
  • 响应时间:用户提交请求到系统第⼀次产⽣响应所花费的时间,在交互式系统中,响应时间是衡量调度算法好坏的主要标准。 

 

posted @ 2021-11-25 22:26  小猴子_X  阅读(156)  评论(0编辑  收藏  举报