CPU ------------- 如何提高CPU利用率
-
多道程序设计
编写监控程序,当程序无须使用CPU时,监控程序就把另外的正在等待CPU的程序启动。 -
分时系统
程序运行模式变成了一种协作模式,即每个程序运行了一段时间以后都主动让出CPU给其他程序,使得每个程序都有机会运行一段时间 -
多任务系统
将程序任务抽象为进程,所有的应用程序都以进程的方式运行,每个进程都有自己独立的地址空间,进程之间的地址空间相互隔离。CPU由系统进行分配,每个进程根据进程优先级的高低都有机会得到CPU。采用抢占式策略,系统可以抢占式剥夺CPU资源并且分配给它认为目前最需要的进程。每个进程都可以分配一个较短的时间片,系统负责快速切换。
内存 ------------- 如何将计算机上有限的物理内存分配给多个程序使用
- 地址空间不隔离。所有程序都直接使用物理地址,程序所使用的内存空间不是相互隔离的。
- 内存使用效率低。由于没有有效的内存管理机制,通常要一个程序执行时,监控程序就将整个程序装入内存然后执行。
- 程序运行的地址不确定。因为程序每次需要装入运行时,我们都需要给它从内存中分配一块足够大的空闲区域,这个空闲区域的位置是不确定的。
解决办法:增加中间层,即使用一种间接的地址访问方法。整个想法是这样的,我们把程序给出的地址看作是一种虚拟地址,然后通过某些映射方法,将这个虚拟地址转换成实际的物理地址。这样,只要我们能够妥善地控制这个虚拟地址到物理地址的映射过程,就可以保证任意一个程序所能够访问的物理内存区域跟另外一个程序互相不重叠,以达到地址空间隔离的效果。
分段(Segmentation)
思路:把一段程序所需要达到内存空间大小的虚拟空间映射到某个地址空间。
分段的方法解决了1和2两个问题,但是对于内存使用效率问题并没有解决。分段对内存区域的映射还是按照程序为单位,如果内存不足,被换入换出到磁盘的都是整个程序,这样势必会造成大量的磁盘访问操作,从而严重影响速度,这种方法还是显得粗糙,粒度比较大。
分页(Pagin)
根据程序的局部性原理:当一个程序在运行时,在某个时间段内,它只是频繁地用到了一小部分数据,也就是说,程序的很多数据其实在一个时间段内都是不会被用到的。因此自然想到更小粒度的内存分割和映射的方法,使得程序的局部性原理得到充分利用,大大提高内存使用率。这种方法就是分页。
分页的基本方法就是把地址空间人为地等分为固定大小的页,物理空间也是同样的分法。那么,当我们把进程的虚拟地址空间按页装载到内存中,把不常用的代码和数据保存在磁盘里,当需要用到的时候再把它从磁盘里取出来即可。
图中Process1的VP2和VP3不在内存中,但是当进程需要用到这两个页的时候,硬件会捕获到这个消息,就是所谓的页错误(Page Fault),然后操作系统接管进程,负责将VP2和VP3从磁盘中读出来并且读入内存。然后将内存中的这两个页与VP2和VP3之间建立映射关系。
在页映射模式下,CPU出发的是Virtaul Address,即我们的程序看到的是虚拟地址。经过MMU转换以后变成了Physical Address。
线程
线程是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针,寄存器集合和堆栈组成。通常意义上,一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间(包括代码段,数据段,堆等)及一些进程级的资源。一个经典的线程和进程的关系:
线程私有 | 线程之间共享 |
---|---|
局部变量 | 全局变量 |
栈 | 堆上的数据 |
线程局部存储 | 函数里的静态变量 |
寄存器 | 程序代码,任何线程都有权力读取并执行任何代码 |
打开的文件 |
线程状态切换:
- 运行:此时线程正在执行
- 就绪:此时线程可以立刻运行,但CPU已经被占用
- 等待:此时线程正在等待某一事件发生,无法执行
我们一般把频繁等待的线程称之为IO密集型线程,而把很少等待的线程称之为CPU密集型线程。IO密集型线程总是比CPU密集型线程容易得到优先级的提升。
三种线程模型:
大多数线程都提供了内核线程,内核线程由多处理器或调度实现并发。然而用户实际使用的线程并不是内核线程,而是存在于用户态的用户线程,用户态线程并不一定在操作系统内核里对应同等数量的内核线程。
- 一对一模型
一个用户使用的线程就唯一对应一个内核使用的线程(但反过来不一定,一个内核里的线程在用户态不一定由对应的线程存在)
优点:线程之间是真正的并发,一个线程因为某原因阻塞时,其他线程执行不会受到影响。
缺点:
- 线程数量受限于内核线程的数量,内核线程数量是有限制的。
- 内核线程调度时,上下文切换开销较大,用户线程执行效率降低
- 多对一模型
多对一模型将多个用户线程映射到一个内核线程上,线程之间的切换由用户态的代码来进行,因此相对于一对一模型,多对一模型的线程切换要快速许多。
多对一模型问题是:如果其中一个用户线程阻塞,那么所有的线程都将无法执行,因为此时内核里的线程也随之阻塞了。
- 多对多模型
将多个用户线程映射到少数但不止一个内核上。多对多模型,一个用户线程的阻塞并不会使得所有的用户线程阻塞,并且对用户线程数量也没有限制。在多处理器上,多对多模型线程也能得到一定的性能提升,不过提升幅度不如一对一模型。