CPU组成结构
可以把CPU理解为是寄存器的集合体,然后你需要知道程序计数器,累加寄存器(存储执行运算的数据和运算后的数据),标志寄存器,指令寄存器和栈寄存器只有一个,其他的寄存器一般会有多个。
-
运算器
字面意思理解就是跟运算有关的,简单说就是负责运算从内存读取到寄存器中的数据,可以看作一个数据加工厂,就是对寄存器中的数据做运算,这些运算包含基本的算术和逻辑运算。
- 算术逻辑单元(ALU):主要负责的就是对数据的处理,从而实现对数据的算术和逻辑运算。
- 累计寄存器(AC):通常叫做累计器,是一个通用寄存器,保存ALU计算后的数据结果。
- 数据缓冲寄存器(DR):从内存读取过来的数据,会暂时存放在这个DR中,这里就相当于内存和CPU之间做数据传送的一个中转站。
- 状态条件寄存器(PSW):它保存的主要是由算术指令和逻辑指令运行或者测试的结果建立的各种条件码内容,一般分为状态标志和控制标志。
-
控制器
是控制整个CPU的工作,对于控制器,一般要能够保证程序的正确执行以及能够处理异常事件。
- 指令寄存器(IR):存放操作指令。指令会从内存中先读到DR作缓冲,然后再读到IR,会有一个叫做指令译码器的东西根据IR的内容生成很多的微操作指令,从而去控制其他部件已完成相应的功能。
- 程序计数器(PC):它保存着下一条要执行的指令的地址值,也就是说当一个程序要执行的时候,会把这个程序的起始地址存到这个PC中,如果这个指令被执行的话也不用担心,CPU会自动修改,使得PC存放下一条要执行的指令。
- 地址寄存器(AR):保存着CPU访问内存上的那一块内存的内存地址。
- 指令译码器(ID):简单点就是对指令做分析的,看看你这个指令要干啥。
举例:
首先就是一个指令,表明要把a这个数值做相加操作,需要先把a保存到累加寄存器,而这个指令被保存在内存中的一个内存单元中,这个内存地址比如说就是0100,而此时程序计数器就是保存的这个0100内存地址,要执行程序的时候,CPU去看看程序计数器保存的第一个地址,发现是0100,然后去内存这个0100的位置,看看保存的是啥,一看是一个指令,分析指令,原来是要把0105地址中的值保存到累加寄存器中,然后就开始干活……
内存
内存指的是能够与CPU直接进行数据交换的存储器,放在电脑上就是内存条,正式的名字叫做随机存取存储器,也叫做主存,是电脑中最主要的存储器,英文缩写是RAM。
缓存
把低速设备的数据保存在高速设备上,需要的时候直接从高速设备上将其读取。
磁盘缓存
磁盘缓存是把从磁盘中读取到的数据保存到内存中,下次读取该数据的饿时候不会再从磁盘中去读取,而是直接从内存中读取。
虚拟内存
举个例子:比如说现在内存空间仅剩10M,但是现在有个大小20M的程序需要运行,在没有虚拟内存的情况下,这个程序是无法被运行的,但是有了虚拟内存就可以,虚拟内存通过特定技术把磁盘中的一部分容量作为内存来使用,也就是说会把这个20M大小的程序的部分数据存放在磁盘中的这块虚拟内存中,然后在真正的内存中也存放部分这个程序的数据,在运行这个程序的时候,如果所需要的数据没有在内存中,而是在磁盘中的虚拟内存中,那么就会发生数据交换,把虚拟内存中需要现在用到的数据与内存中这段程序暂时不用的数据进行交换,以此来保证程序的正常运行。
虚拟内存的重要意义是它定义了一个连续的虚拟地址空间,并且 把内存扩展到硬盘空间。
当发生缺页中断时,如果当前内存中并没有空闲的页面,操作系统就必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。用来选择淘汰哪一页的规则叫做页面置换算法,我们可以把页面置换算法看成是淘汰页面的规则。有四种策略:
- 最佳置换算法OPT:理想情况,不可能实现,一般作为衡量其他置换算法的方法。
- 先进先出FIFO:总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
- 最近最久未使用算法LRU:最近一段时间里最久没有使用过的页面予以置换.
- LFU页面置换算法(最少使用页面排序算法)/ clock算法:LFU(Least Frequently Used)算法会让系统维护一个按最近一次访问时间排序的页面链表,链表首节点是最近刚刚使用过的页面,链表尾节点是最久未使用的页面。访问内存时,找到相应页面,并把它移到链表之首。缺页时,置换链表尾节点的页面。也就是说内存内使用越频繁的页面,被保留的时间也相对越长。
进程/作业相关调度算法
-
先来先服务算法:
FCFS算法总是选择最先进入就绪队列的进程/作业,将处理器/内存分配给它。适合CPU密集型作业,不适合IO密集型。
-
短作业优先算法:
SJF算法选择一个或多个估计运行时间最短的作业/进程调入内存/处理器分配给它。
该算法对长作业不利,容易造成饥饿。
-
高优先权优先调度算法:
使用优先级表示作业或进程的紧迫程度,选择优先级最高的作用或进程调入内存或分配处理器。此算法常被用在批处理系统中,作为作业调度算法,也作为多种操作系统中的进程调度,还可以用于实时系统中。
根据高优先级进程能否抢占低优先级进程可将该调度算法分为:
- 非抢占式优先权算法
- 抢占式优先权调度算法(高性能计算机操作系统)
根据进程优先级能否改变分为:
- 静态优先级:优先级在进程创建时确定,在进程整个运行期中保持不变。
- 动态优先级:根据进程运行状况动态调整进程优先级。
-
高响应比优先调度算法(动态优先级):
主要用于作业调度,是FCFS与SJF的综合平衡。在每次作业调度时,先计算各作业响应比,选择响应比最高的作业调入内存。响应比 = (等待时间 + 要求服务时间) / 要求服务时间
-
时间片轮转调度算法:
时间片轮转法一般用于进程调度,每次调度,把CPU分配队首进程,并令其执行一个时间片。 当执行的时间片用完时,由一个记时器发出一个时钟中断请求,该进程被停止,并被送往就绪队列末尾;依次循环。
-
多级反馈队列调度算法:
多级反馈队列调度算法是时间片轮转调度算法与优先级调度算法的综合,通过动态调整优先级与时间片的大小,该算法可兼顾多个方面,且不必估计进程运行时间。
设置多个就绪队列,并为各个队列赋予不同的优先级。在优先权越高的队列中, 为每个进程所规定的执行时间片就越小。
当一个新进程进入内存后,首先放入第一队列的末尾,按照先来先服务原则排队等待调度,如果能在一个时间片中完成,就可撤离;如果未完成就把它移到第二队列的末尾等待调度。系统会在高优先级队列为空的时候再去执行下一优先度队列的进程。
多级反馈队列调度算法对于终端型作业用户,短作业优先;对于短批处理作业用户,周转时间较短;对于长批处理作业用户,不会产生饥饿现象。
分页/分段 <------ 内存管理方式
分页和分段是两种不同的内存管理方式,而目前应用较为广泛的一种储存管理方式是两者的综合,“段页式储存管理方式”,程序的地址空间划分为多个拥有独立地址空间的段,每个段上的地址空间划分为大小相同的页。这样既拥有分段系统的共享保护,又拥有分页系统的虚拟内存功能。
补充:实际上还有一种方式是分块,但已经被淘汰了。
分页是将将用户程序地址空间分为若干固定大小的区域,称为“页”,典型的页面大小为1KB。相应的,也将内存空间分为若干个物理块或页框(frame),页和块的大小相同。这样可将用户程序的任一页放入任一物理块中,实现了离散分配。(页式管理通过页表对应逻辑地址和物理地址)
分段是为了满足用户要求而形成的一种储存管理方式。它把用户程序的地址空间分为若干个大小不同的段,每段可定义一组相对完整的信息。在储存器分配时,以段为单位,这些段在内存中可以不相邻接,所以也同样实现了离散分配。(段式管理通过段表对应逻辑地址和物理地址)
还有一种方式是段页式管理机制,就是结合上面两者优点。将内存分为若干段,每个段又细分为若干页。也就是说,段与段之间以及段内部都是离散的。
分页和分段的异同:
共同点:
- 分页机制和分段机制都是为了提高内存利用率,较少内存碎片。
- 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。
区别:
- 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
- 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。
两者不同见:https://www.jianshu.com/p/a805e2410fbe
页面置换算法:https://www.cnblogs.com/lnlin/p/11219150.html
细节补充:https://mp.weixin.qq.com/s/MfLE6TrjlCeH3xT1YSATHg
0号/1号/2号进程
Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2)
0号进程,称为idle进程,由系统自动创建,作用是进程调度、交换
1号进程,称为init进程,由idle通过kernel_thread创建,Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程。
2号进程,称为kthreadd进程,由idle通过kernel_thread创建,负责所有内核线程的调度和管理。
僵尸进程:僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。(有危害,进程号会被占用导致无法开新的进程)
孤儿进程:如果父进程先退出 ,子进程被init接管,也就是上面的1号进程,子进程退出后init会回收其占用的相关资源。(会被自动解决,没有危害)
避免僵尸进程的措施:
- 父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程被挂起。
- 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收。
- 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD,SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号。
杀死僵尸进程的措施:
无法直接杀死僵尸进程,只能通过杀死僵尸进程的父进程,init进程会接管僵尸进程并进行清理。