存在内存的特定地址,启动执行,检查计算机硬件java
加载位于硬盘特定地址的BootLoader,管理权交给BootLoadernode
BootLoader加载os,管理权交给os算法
应用程序主动向操做系统发起请求指令(syscall)。同步或异步chrome
应用程序执行中被动触发操做系统执行指令。应用程序意想不到的行为。除以零、访问未知地址等。同步。应用能够感知shell
外设向操做系统发出请求,须要操做系统提供支持。异步。对应用透明编程
陷阱指的是当异常或者中断发生时,处理器捕捉到一个执行线程,而且将控制权转移到操做系统中某一个固定地址的机制。现代操做系统是由中断驱动的,中断分为硬件中断和软件中断。而陷阱属于一种软件中断。若是计算机没有进程要执行,没有用户响应请求,操做系统将等待某个事件的发生。而事件老是由中断或者陷阱引发的windows
操做系统为保证系统正常运行,会提供两种操做模式:api
两种模式不会互相干扰。操做系统须要硬件支持来提供双重模式操做:当用户进程进行非法操做(非法指令或非法地址访问)的时候,硬件会向操做系统发出陷阱信号,致使控制权转移到操做系统,操做系统结束用户进程并给出错误信息数组
运行中的程序。分为用户进程和系统进程浏览器
内存是cpu和io设备能够共同访问的数据仓库。若是cpu须要访问磁盘数据,首先生成io调用将数据加载进内存,以后才能直接访问
编译器会应用程序生成的地址
实际内存条(主存)和硬盘提供的可用地址
操做系统在其中扮演者预先创建虚拟地址到物理地址映射关系的角色,而且还限制了每一个应用访问虚拟地址的空间。若是cpu执行某个应用程序时,访问了不属于它的空间,就会产生一个内存访问异常,操做系统会接管并执行相应的异常处理代码
内存中空闲的,未被使用的空间
分配单元之间,没被使用的空闲空间
已分配给该应用,可是该应用未利用到的空闲空间
合理的内存管理就是减小这些内存碎片
两种硬件方案:分段、分页
将应用分红多个段:堆、运行栈、程序数据、程序text段。在虚拟地址是连续的,可是映射到物理地址是分离的
分段寻址机制:在分段机制中,要将虚拟地址映射到物理地址,虚拟地址被划分红两个部分,第一段为segment number,第二段为segment offset。cpu根据segment number去segment table中定位到该number对应物理内存的base地址,及该segment长度limit。而后经过检查offset是否小于等于limit,若是不是就触发异常,若是是该虚拟地址就成功映射到物理地址base+offset
segment table是由操做系统预先创建,并存入硬件
分段在cpu中使用较少,分页使用较多
分页相似分段,也是将内存分红多个部分
在虚拟内存中,这些部分称为page(页),在物理内存中,这些部分称为frame(帧)。虚拟地址由page number和page offset定位,物理地址由frame number和frame offset定位,page number与frame number大小能够不一致,可是二者的offset必须一致,而且page size和frame size大小一致。
硬件寻址的时候根据虚拟地址划分出page number和page offset,并经过page table和该table的base地址查询page number到frame number的映射关系,最后定位到frame number,因为page offset与frame offset一致,因此最终物理地址就是frame number + page offset
分段与分页惟一不一样的地方在于每一个segment的大小不一样,而每一个page大小相同(1k、4k等)。因此segment table须要记录[segment number -> 物理内存base地址,segment长度limit]映射关系。而page table只须要记录[page number -> frame number]映射关系
经过分段或分页中,虚拟内存是连续的,可是定位到物理内存能够是非连续的,这样提升了内存利用率,减小了碎片
page table由操做系统创建
假设page size为1k(2^10),64位操做系统须要创建的page table大小达到2^(64-10)=2^54,这么大的page table cpu和内存都没法存放,这致使空间开销大。即便内存能够存下,每次寻址都要先查page table再查物理内存,涉及到两次内存查询,这致使时间开销大
每次cpu的MMU(内存管理单元)寻址的时候都会查询page table,这样致使时间开销很大。TLB是MMU中包含的一个缓存,缓存了page table的数据,空间很小速度很快
为了减小TLB查询miss,应用须要保证访问局部性
以二级页表说明
将虚拟地址分红三部分:
内存中创建两个page table,一级page table中存储二级page table的base地址,二级page table存储frame number
寻址方式:
这种方式之因此能减小空间,能够经过64位系统、1k page size状况来讲明:
只用一个page table会致使须要创建大小为2^54的page table,根据这个page table中的信息判断虚拟地址是否有对应的物理地址
采用二级page table会让一级page table成为二级page table的索引,若是索引不到二级page table无需创建,索引到才须要创建。当虚拟地址远远大于物理地址的时候,会极大减小二级page table的item
结合上述结果,可得若是更多级page table会大大减小所需空间,不过也会带来另一个问题:屡次访问内存page table导致时间开销大。这个能够经过TLB解决
须要为每一个进程分配多级页表,以保证进程隔离,进程不会越界访问其余进程的虚拟地址。隔离以后,每一个进程看到的虚拟地址可能一致,但映射的物理地址不会相同,这一层经过操做系统保证
多级页表会致使管理页表更麻烦,而且大小受虚拟地址影响,并且多级页表的状况下须要为每一个进程分配页表,因此空间开销依然不小
反向页表不一样,它根据物理地址索引虚拟地址,大小受物理地址限制,而且全部进程共享同一张页表,因此空间开销很小。须要区分每一个物理内存对应的应用,就须要引入pid(进程编号)
因为cpu只能拿到虚拟地址,利用反向页表的时候,须要遍历页表,匹配指定pid和虚拟地址,最终肯定物理地址。至关于遍历数组的值,肯定索引,时间开销较大
优化方案
基于hash函数方案:能够经过传递pid和虚拟地址,执行一段hash函数,定位到索引,即物理地址。缺点是设计高效少碰撞的hash算法难度较大,而且访问hash表会致使多出一次内存访问,这个能够经过TLB缓解
内存不够的状况下的解决方案之一。将应用使用的内存分红多个页管理,当内存不够用的时候,将应用没有使用到的页交换到磁盘,当内存足够的时候,将应用须要的页交换到内存。经过操做系统内核和MMU完成
内存置换的时候,须要一些信息,这些信息存在页表项中
页表由页表项组成,每一个页表项包含
虚存技术将内存置换交给了操做系统,但一样提出了对应用程序的要求。它但愿程序可以保证局部性
当程序达到时间局部性和空间局部性,就说程序的局部性很好,它能让内存置换次数更少,使得访问虚存就像访问内存同样简单、快速
当访问虚拟内存没法映射到物理内存时,会产生缺页中断,流程为:
局部页面置换算法
当出现缺页中断而且没有足够的物理页面时,须要置换算法保证将一部分页面写到磁盘,并腾出相应的空间。
最优置换算法但愿保证将要置换的页面在后面很长一段时间都不会访问到
不过这种状况较理想,由于没法预测将来应用会访问到的页面,因此这种方式没法实现。不过这种算法能够做为一个理想评价标准
局部页面置换算法
操做系统维护一个链表,维护使用过的页信息。链表采用先进先出原则,在缺页中断发生时,链表表头的页会被淘汰。效果较差
局部页面置换算法
最久未被使用的页优先被淘汰
采用栈或链表实现:每次访问页面,若是以前访问过,则替换到表头或栈顶,并淘汰表尾或栈底的元素。每次访问页面都要遍历一次链表或者栈,时间开销较大。若是采用hash表,空间开销大
局部页面置换算法
将页组织成一个环形链表,当出现缺页中断时,指针沿着环形链表不断向后转动,若是发现访问位为1的则将它置为0,若是碰到访问位为0的则淘汰该页
访问位是在cpu访问该页以后置为1的,表明该页最近被访问过。这个算法至关于给了两次机会,当须要置换时,会检查该页,若是为1,则置为0,表示只有最后一次机会留在内存。若是一个页常常被访问,操做系统置换检查时,该位应该老是1
局部页面置换算法
上述CLOCK算法没有考虑须要置换的页面是否被修改过。
加强CLOCK算法思想是优先淘汰没有访问而且没有写的页。它引入修改位,将访问位与修改位视为二元组,在环形链表中:
局部页面置换算法
淘汰使用最少的页
这种置换算法有两个问题:
第二个问题的解决方案是,定时将计数寄存器右移,保证一直未被使用的数据,最后会指数级衰减
给每一个应用分配的物理页面越多,缺页率反而越高的异常现象
一个进程当前正使用的逻辑页面集合。由二元组W(t,△)
|W(t,△)|能够量化应用局部性,若是页面数越大,局部性越差
当前时刻,进程实际驻留在内存中的页面集合,大小等于操做系统分配给该进程的物理页数,内容取决于操做系统采用的页面置换算法。
工做集与常驻集:进程不断访问内存页,造成工做集集合,访问页的时候会查询常驻集中页,若是不存在则引起缺页中断
以前介绍的FIFO,LRU,CLOCk,加强CLOCK都是局部页面置换算法,只考虑某个进程内页面置换的状况。全局页面置换算法会考虑全部进程进行页置换的状况。
为何须要全局置换算法?
每一个进程工做集不断变化,程序局部性也在不断变化,操做系统能够根据这些信息动态调整常驻集大小,避免浪费或者资源不够。因此,全局页面置换算法相比局部页面置换算法,更加合理
为何介绍局部置换算法?
既然全局置换算法更合理,为何介绍局部置换算法呢?由于有的局部算法如FIFO,LRU,也能够用在全局;有的系统更加依赖局部置换算法来保证部分程序出现抖动不会影响全局系统
全局页面置换算法
常驻集只保存工做集中的页面,全部不在工做集中的页面都要置换出去。每次应用访问内存页的时候,都会进行置换算法
全局页面置换算法
思想是根据缺页率动态调整常驻集大小。当缺页率太高时,增大常驻集(物理页帧数);当缺页率太小时,减少常驻集。保证缺页率在一个合适的范围内
实现:
相比较工做集页置换算法,缺页率置换算法以缺页率为参考依据,工做集置换算法须要在每一个时刻执行算法,缺页率算法只是在缺页的时候才会执行算法
当进程数愈来愈多,分配给每一个进程的物理页数愈来愈少,致使常驻集永远没法包含工做集,导致大量缺页中断,操做系统频繁进行内存置换,cpu利用率大大下降。这种现象称为抖动
抖动出现表明操做系统的负载太高,这种负载每每是过多的进程数或不合理的物理页数致使的。为了缓解这种状况,操做系统须要保证:
实际状况,第一个方案较难实现,每每采起第二个方案
关联:
区别:
进程包含以下信息:
操做系统用来表明每一个进程的数据结构,简称PCB。PCB能够描述进程的基本状况和状态变化的过程,是每一个进程的惟一标识
包含三类信息:
通用操做系统会采用链表而不是数组来组织PCB,由于进程会不断建立和销毁,因此须要不断添加和删除操做,采用链表开销更小
进程生命周期能够分为:
其中须要说明的是Running与Ready之间的状态转换:内存中有多个就绪的进程须要执行,当进程A执行时间片用完以后,操做系统会切换到进程B,让进程A进入就绪状态,进程B进入运行状态
进程挂起就是当内存不够用的时候,将进程换出到磁盘。挂起分为两种状态:
挂起涉及到的状态转换:
进程激活就是将进程从磁盘换入到内存,涉及到的状态转换:
操做系统根据进程状态,来分开管理进程:
操做系统根据进程的状态,决定将它插入哪一个队列中。当进程状态变化时,操做系统会从原队列取出,插入新队列
轻量级进程,是进程中的一条执行流程。一个进程中的不一样线程,共享相同的数据区、代码区和打开的系统资源,可是每一个线程有本身独立的PC、栈、通用寄存器,以便维护各自的执行状态。进程是资源分配的单位,线程是cpu调度的单位
操做系统采用数据结构TCB来表示线程,线程与进程同样,也拥有就绪、阻塞、运行三种状态,以及状态之间的转换关系
优势:
缺点:
例子:
线程所需的资源:
由库函数实现的线程是用户线程。采用库来支持线程的建立、销毁、调度,操做系统并不知道用户线程的存在
优势:
缺点:
由内核维护PCB和TCB
优势:
缺点:
案例:
内核支持的用户线程,结合了用户线程管理开销小和内核线程稳定性高的优势。
案例:
用户线程与内核线程映射关系:
进程切换涉及的几个关键操做:
其中上下文主要指进程使用的寄存器,如PC寄存器、栈寄存器、通用寄存器。这些信息在切换以前必须保存,以便以后恢复执行
操做系统为存储这些进程,提供了多种队列:
int pid = fork();//建立一个进程,并返回子进程id if(pid == 0){ //子进程返回值为0 exec("program",argc,argv0,argv1,...) }else if(pid > 0){ //父进程返回值为子进程id ... }else{ //错误 ... wait(pid);//等待子进程结束 }
在fork复制进程的时候,会复制全部进程信息,只有其中各自子进程id不一样,使得fork返回值不一样
Unix/Linux采用exec加载进程,绝大部分状况下fork后会使用exec,保证拷贝的子进程可以加载新程序。如上一节代码,exec会将当前进程全部信息替换为program进程信息
wait()用于父进程等待子进程结束
不一样次序会有不一样结果:
exit()用户进程资源回收
其中exec的时候可能出现两种状况:
从就绪进程中挑选一个占用cpu的过程,若是有多cpu,还须要提早选出一个可用的cpu
进程调度涉及到上下文切换
进程调度时机,首先须要知足这两个条件其中一个才能产生调度:
其次,还须要分状况讨论具体调度时机:
非抢占系统:
可抢占系统:
长进程:执行时间较长的进程
短进程:执行时间较短的进程
进程调度算法之一。优先服务先入队列的进程
优势:
缺点:
进程调度算法之一。优先服务短进程。涉及到两个技术点:
优势:
缺点:
进程调度算法之一。根据就绪队列中进程列出以下公式:
R=(w+s)/s
等待时间越长,R越大;执行时间时间越长,R越小。该算法优先服务R最大的进程。可见,它至关于短进程优先算法的改进版
优势:
缺点:
调度算法之一。指定时间片大小为N,按前后顺序取出就绪队列中的进程执行,时长不超过N,执行完成以后,取下一个进程继续执行。取进程的顺序与先来先服务一致,可是每一个进程执行时间不得超过N
优势:
缺点:
经验规则:一般设置成10ms,能够保证上下文切换开销在1%之内
调度算法之一。将就绪队列分为多级子队列,根据每一个队列具体状况的不一样,采用不一样的算法,是一种综合使用全部算法的一种算法
多个子队列之间采用时间片轮转算法来调度,每一个队列保证必定的cpu执行时间。
如:两个队列,前台交互式,占80%时间,后台批处理,占20%时间。则每一个执行周期会执行4次前台进程和1次后台进程
多级队列算法改进版。多级队列算法没有考虑到实际队列中进程执行时间,有的较长但放在了前台队列,致使真正响应快速的进程没有获得更高的优先级
将多级子队列按优先级从高到低划分,优先级越低,分得的时间片越大,适合执行批处理任务,优先级越高,分得的时间片越小,适合执行交互式任务。执行顺序从高到底,高优先级队列执行完了才执行低优先级队列,在规定时间片内每执行完的进程,被下放到低一级的队列,但获取到了更多时间片
优势:
缺点:
这是实际系统会采用的算法
按用户组重要程度,给他们使用的系统资源划分优先级,没用完的资源用比例划分
不作详细介绍
有些系统不只要保证功能性,更要保证明时性,但愿能再可预测的时间以内完成某个功能。它对吞吐量要求并不高,可是对实时响应要求很是高。根据实时程度,分为两种:
一个实时任务中涉及的重要概念
系统每每由多个实时任务组成,多个实时任务一般是周期性请求,如图周期为5
其中假设周期为5,最大执行时间为1,则使用率为1/5
为保证调度系统实时可控,须要确立众多任务调度顺序,有两种方法
任务周期越短(速率越快)的优先级越高
由于任务的周期(速率)是调度以前就能肯定好的,因此它是静态优先级调度算法
请求的任务中,截止时间越早,优先级越高
任务不一样,截止时间也不一样,因此只有处理任务请求的时候才能知道截止时间,因此它是动态优先级调度算法
选取其中一个cpu做为主,进行调度和资源访问,无需同步,可是没法利用多处理器
简称SMP,每一个cpu运行本身的调度程序,访问共享资源的时候会须要同步,同步开销较大,可是更加通用。多处理器调度实际上是考虑如何将进程分配给cpu,有两种方案:
静态进程分配:为每一个cpu维护一个就绪队列,进程一旦分配到这些队列,会一直属于该队列,进程一旦执行就不会被切换,至关于将进程绑定给cpu
动态进程分配:为全部cpu维护一个共享就绪队列,进程会分配给空闲可用的cpu执行,中途会被切换
低优先级进程阻塞高优先级进程的现象
如三个进程A,B,C,优先级A<B<C
这样B就阻塞了C的执行
优先级反置的解决方案之一
当低优先级占有资源而且高优先级进程申请资源时,一旦低优先级进程被阻塞(如A被B阻塞),就让它的优先级继承高优先级进程(让A继承C的优先级),这样就能解除阻塞顺利抢占cpu并执行
优先级反置的解决方案之一
当进程占用资源时,将它的优先级提高为M(M=全部可能占有该资源进程的最高优先级),保证让该进程不会被阻塞
缺点:该方案的缺点明显,它的滥用优先级提升的功能,当全部进程优先级同样的时候,这种方案也没用了
优势:
缺点:
之因此进程并发会出现问题,是由于不少进程操做都不是原子操做,致使执行一半被中断,并切换到另外一个进程,使得数据正确性和一致性受到影响
原子操做是一组不可中断的操做,里面可能涉及多个步骤,要么所有成功,要么所有失败,不可能出现部分红功部分失败的状况
进程之间有三种交互状况:
进程隔离:各进程资源独立,并发不会致使问题
共享资源:访问共享资源,会带来三个问题
操做系统要知足共享资源的同时又能提升效率,就必须提供一种高效的同步互斥机制
通讯协做:经过互相通讯来传递信息
将访问共享资源的一片代码称为临界区
进入区 临界区 退出区 剩余区
临界区访问规则:
经过禁用硬件中断能够很好的实现对临界区访问的同步,它能够保证进程不会被中断,也没有进程上下文切换,也没有并发执行。它的思想是经过限制并发、并行,保证进程执行的正确性和一致性
优势:
缺点:
现代操做系统提供了禁用中断及恢复中断的指令,可是不多使用
基于软件方式的实现两个线程同步的经典算法
思想是提供两个共享变量,并组合使用,来表明是否能够访问临界区。能够很好的协调多个线程访问,而且符合临界区访问规则
优势:
缺点:
经过编程抽象的一种同步机制,底层依赖于硬件支持,保证一个时间点只能有一个线程访问共享资源。涉及到一个变量和两个操做
锁操做必须保证是原子的。cpu提供了两个原子性操做,库函数经过使用这两个原子操做,来实现锁语义
cpu提供的原子操做
class Lock{ int value=0; WaitQueue q; void lock(){ while(testAndSet(value)) block(currentThread);//将当前线程放入阻塞队列,放弃cpu。同时调度其余线程;若是不作任何操做,就是忙等待 } void unlock(){ value=0; wakeup(otherThread);//将阻塞队列中的线程唤醒到就绪队列 } }
优势:
缺点:
基于锁方案的同步机制更加经常使用
经过编程抽象的一种同步机制。由一个整数、两个方法、一个队列组成
其中信号量提供给用户用,但P()和V()方法由操做系统来实现,优先级比应用进程的优先级,不会被中断,保证了两个方法的原子性
信号量是一种公平的同步方法,先阻塞的线程先进等待队列,而且优先被唤醒。相较而言,自旋锁没法保证公平
用信号量解决生产者消费者问题
在早期操做系统中使用较多,如今不多使用,由于使用复杂,容易出错。而且信号量中P是操做系统来实现,优先级高,可能会保持阻塞,造成死锁
不少现代编程语言(java)使用的一种同步模型,是一种高级同步机制
由如下成分组成:
管程解决生产者消费者问题
其中count就是条件变量
其中Wait操做会释放锁,避免出现信号量中的死锁问题,使用相对容易
在T2唤醒T1以后,为了高效不切换,优先继续让T2线程执行(没法肯定到底哪一个执行),直到T2释放锁,T1才恢复执行。java中采用此方案
while(count==n){ wait() }
因此上述代码中,wait的线程被唤醒后,可能仍是没法执行,致使count的值可能遭到修改,因而必须使用while循环从新判断一次
在T2唤醒T1后,T2释放缩,T1抢占并执行(肯定T1抢占)
if(count==n){ wait() }
因此上述代码,wait的线程被唤醒后,会抢占执行,期间不会有其余线程修改count的值,因此无需重复判断
hoare侧重于做为原理讲解管程执行流程,而henson才适合用在真正的系统
五个哲学家,五根筷子,每一个人两边都放了筷子,组成环路。哲学家有两个操做:
可能出现一种状况,全部哲学家拿起左边的筷子,等着右边的筷子,最后都没法进食,活活饿死。这就是所谓的死锁状况
解决方案:
有四种状况:
根据读者、写者的实现机制不一样,可能采用不一样的优先策略:
java的读写锁就是利用管程思想实现了读者-写者机制
多个进程之间互相等待对方释放资源,而且永远没法结束的一种现象
死锁出现的必要条件:
资源互斥:至少有一个资源是互斥类型的,不能容许两个或两个以上的进程同时访问
占有并等待:至少有一个进程占有资源并等待另外一部分资源才能完成任务
非抢占:资源是不可抢占的,必须由占用进程自愿释放
循环等待:必须存在相似以下现象
只有知足这四个条件,才会出现死锁
针对死锁的处理方法:
提早预防死锁,死锁的必要条件有四个,只要其中任何一个不知足,死锁就不会出现
在进程申请资源的时候动态判断有没有出现死锁的可能,若是有就不容许进程使用资源
算法:当进程请求资源时,系统判断资源分配后是否处于安全状态,若是是则分配,不然暂停分配
安全状态指:
一系列进程P1到Pn,保证Pi申请的资源<=当前可用资源+全部Pj占有的资源,j<i。若是Pi申请的资源不能当即分配,暂停Pi,等到全部Pj完成
安全状态与死锁的关系
是一种基于安全状态判断的死锁算法
核心思想:每一个客户会申请须要的最大资金量,银行会根据你已经占有的资金,力所能及的将剩余部分借给客户。客户在借完资金后会及时归还,保证银行有充足的储备继续借款
数据结构:
Need=Max-Allocation
算法:
Finished[i]=false,Need[i] < Allocable
的进程,表示i能够申请资源,不然执行步骤4Work += Allocation[i],Finished[i]=true
,由于i申请的资源最后会被回收,因此忽略分配过程,直接跳到回收环节。执行步骤2基于银行家算法的思想,判断会不会出现死锁。在完成算法后,存在Finished[i]=false,表明进程i会致使死锁状态,称i为死锁进程
经过结束进程来恢复死锁:
显而后者更好,可是会根据以下条件考虑该优先终止哪一个进程:
经过抢占进程资源来恢复死锁:
将死锁进程回退到安全状态,并抢占它的资源,开销小,可是会出现饥饿现象——进程恢复后又进入死锁状态,继续被抢占
简称IPC,进程间交互信息
能够分为阻塞与非阻塞
根据通讯链路的缓冲容量可分为
进程间基于中断传递消息的一种机制。如经过ctrl+c终止运行的程序
原理:应用进程注册信号处理函数,当出现中断时,操做系统会根据信号回调信号处理函数。ctrl+c是操做系统默认给每一个进程添加的信号处理函数
缺点是局限性大,只能传递信号类型的消息
进程基于内存文件的通讯方式
在命令ls | more
程序中
这样就在内存中创建了两个进程的消息通道
内核提供一个FIFO队列,提供给不一样进程通讯
优势:
缺点:
优势:
缺点:
实现机制:
基于页表来实现。不一样进程有本身的页表,操做系统将它们的页表映射到同一个物理地址空间,就完成了进程间共享内存
操做系统中将磁盘数据组织成文件系统,提供对这些持久化数据的操做
功能:
文件系统须要被挂载才能被访问,它被挂载的目录称为挂载点
根据文件系统的类型分为:
分布式文件系统会产生安全性、一致性等问题,比本地磁盘文件系统更复杂
文件系统组织磁盘上数据的方式,并抽象了一些属性用于简化这些持久化数据的管理
文件属性:
将文件分为两部分:
目录是一种特殊的文件,其内容是文件索引表,表的每一项是二元组<文件名,指向文件的指针>。操做目录就是操做文件索引表
应用程序都是经过系统调用来访问目录
让多个文件名指向同一个文件,看起来就像给文件起了别名
有两种起别名的方式:
ln src dest
ln -s src dest
可能出现文件子目录指向父目录,致使出现循环目录的状况,这种状况会导致目录遍历永远没法结束
常见的处理方式是设置一个最大遍历层数
文件系统中的名字解析就是根据文件路径,读取文件信息
如/bin/ls
解析过程为:
进程每读取文件的时候,都要从根目录进行名字解析,会致使效率很低。因此操做系统为每一个进程设置了一个目录PWD,表明当前工做目录。这样当访问一些当前目录存在的文件时,不须要再从根目录开始遍历
这种机制提供了一种基于相对路径来访问文件的方式
简称VFS,是对底层各个不一样文件系统的一个抽象(各个磁盘文件系统和网络文件系统),对上层提供一个统一的api(open、close、read、write)
全部文件系统实现不一样,但有些公共数据结构仍是一致的
简称superblock,每一个文件系统有一个,记录了文件系统相关信息:文件系统的类型、数据块个数与大小、空闲块个个数与大小等信息
在文件系统挂载时加载到内存
简称inode,每一个文件有一个,记录了文件相关信息:文件大小、数据块位置、访问权限、拥有者等
在访问文件时加载到内存
简称dentry,每一个目录项(文件、目录)有一个,记录了目录相关的信息:文件控制块的位置、父目录、子目录等
与文件控制块不一样的是,它侧重于对目录信息的描述,并且VFS利用目录项控制块将文件系统组织成树状结构
在遍历目录时会加载到内存
文件系统组织视图
文件系统存储视图
其中
内存中缓存磁盘数据块的一部分区域
在读的时候提供预读取:预先读取后面的数据块
在写的时候延迟写:写到缓存就返回,操做系统定时flush
简称page cache。因为虚拟内存是基于页来管理内存,文件系统基于块来管理文件数据,页和块大小不一样,须要一个机制统一二者的管理方式
页缓存实现中屏蔽了底层数据块的管理,上层统一提供基于页的管理方式,供虚拟内存使用
在应用进程进行内存映射mmap(将文件映射到内存)或者文件读写时,虚拟内存会先访问页缓存,找不到就会出现缺页中断,触发对文件系统的查询,而后再把数据加载到页缓存
不少文件操做都须要搜索文件,为了保证只在第一次读取的时候搜索,操做系统须要在第一次访问的时候打开文件,返回一个文件描述符,文件描述符就是一个索引,指向打开文件表中的打开文件,操做系统在该打开文件中维护了一些状态信息,保证之后在操做该文件的时候无需再次搜索
操做系统会建立一个全局打开文件表,同时也会为每一个进程建立一个打开文件表,其中维护了这些信息:
读取一个文件的流程:
多个进程打开文件的时候,可能会出现并发安全问题
操做系统提供了两种文件锁:
当文件须要磁盘空间的时候,文件系统须要为该文件分配数据块
经常使用分配算法:
分配的时候主要考虑两点:
根据文件须要的块大小,查找磁盘中空闲块,发现有足够大小的,就分配给文件
优势:
缺点:
根据文件须要的块大小,找到磁盘中各个空闲块进行分配,并经过链表指针联系到一块
优势:
缺点:
根据文件须要的块大小,找到磁盘中的空闲块进行分配,并单独利用一个块存储索引这些数据块
优势:
缺点:
实际unix文件系统(UFS)会结合索引分配和链式分配组成多级索引分配算法
要为文件分配数据块,首先得知道全部空闲块在哪。先来看几种空闲块管理机制:
位图:用位图表示全部块,0表示空闲,1表示已分配
链表:在一个空闲块中加入指针指向下一个空闲块,造成链表。
索引:经过一个块存储索引,记录这些空闲块的位置
实际系统是组合这几种方式
机械硬盘都是经过磁头进行磁盘寻址,若是磁盘越大,寻址时间越大。因此将磁盘划分红多个分区能够减小寻址时间,提高磁盘访问速度,可是若是同时在多个分区之间切换也会带来性能的降低
分区就是一组柱面的集合,每一个分区能够视为一个独立的磁盘
分区组织方式:
其中第二种方式,在一个分区使用多块磁盘,能够基于此方案提高文件系统的可靠性与吞吐量,利用到的就是磁盘冗余技术
基于上述第二种方案,能够利用冗余磁盘提升吞吐量(并行)与可靠性(冗余)
磁盘冗余阵列简称RAID,是一种基于冗余磁盘的思想实现的磁盘管理技术,经常使用的有RAID-0,RAID-1,RAID-5等
能够经过文件系统或者RAID硬件控制器来实现
将数据块分红多个小块,并行存储在独立的磁盘上,这种方案能够提高吞吐量
向两个盘写,从任意一个读,利用其中一个作镜像盘来提升可靠性。这种基于冗余盘的思想同时缓解了一个盘的读压力,至关于也会提高读性能
利用一个盘作校验盘,其余盘基于RAID-0的方案拆分小块的基础上并行访问,校验盘的数据是其余盘数据的校验和。这种方案能够保证即便其中一个数据盘坏了,也能基于校验和和剩余磁盘来恢复它的数据。同时由于利用到了RAID-0的并行方案,也提高了读写性能
与RAID-4思想一致,可是为避免校验盘称为瓶颈,取消惟一的校验盘,在每次数据写入时,将计算好的校验和轮流存放在全部磁盘上,造成一个分布式系统的负载均衡算法
RAID-4和RAID-5都是基于块计算校验和,而RAID-3是基于位来计算校验和
RAID-5每次写都会计算出一个校验块,保证最终能够容忍一个磁盘坏掉。RAID-6则是计算出两个校验块,保证能够容忍两个盘坏掉
RAID嵌套技术之一
让两个磁盘采用RAID-0方案并行读写,再利用两个盘做为镜像盘同步数据。安全性、性能较好,成本较高
RAID嵌套技术之一
让两个盘采用RAID-1方案一个主一个备,再利用两个盘一主一备,先后二者采用RAID-0的方案并行读写。安全性、性能较好,成本较高
能够分为三类:
各设备有不一样的I/O实现。根据cpu与这些设备的交互,将I/O分为阻塞I/O、非阻塞I/O、异步I/O
用户进行读写操做后,须要等待设备完成读写操做,并返回结果
用户进行读写操做后,不须要等待返回结果
用户进行读写操做后,不须要等待返回结果,可是操做系统完成读写操做后会通知用户
cpu经过北桥与内存、显卡等高速设备链接,经过南桥与I/O等设备链接
cpu依赖I/O设备控制器与I/O设备交互,设备控制器结构为:
cpu与I/O设备交互的三种方式:
cpu经过I/O端口访问I/O设备
MMU将I/O设置的存储地址映射到内存,cpu经过访问内存来实现对I/O设备的访问
I/O访问流程就是从用户进程上到下的访问流程,当完成访问后设备经过中断,从下到上通知用户进程
cpu和I/O设备之间基于两种方式交换数据:
程序I/O:直接经过cpu指令控制I/O设备交互数据
DMA:cpu让I/O设备经过DMA直接读写内存,cpu访问内存便可获得这些数据
完成数据传输后,设备须要通知cpu,有两种机制:
轮询:cpu轮询控制器寄存器,获取设备状态信息,根据状态进行操做
中断:设备经过中断将事件反应给cpu。cpu每执行一条指令后都会进行中断检查,发现中断后立马执行中断请求,而后再恢复执行原来的进程
设备控制器直接访问内存的一种机制
基于DMA和中断的方式读取磁盘数据的流程:
磁盘工做机制
读取数据其实就是磁头定位到指定的磁道,而后从磁道读取指定扇区的内容
寻道时间:磁头定位到磁道所花的时间
旋转延迟:在磁头定位到磁道后,磁盘不断旋转,直到磁头发现数据所在扇区,这个时间开销就是旋转延迟
磁盘I/O传输时间=等待设备可用+等待传输通道可用+寻道时间+旋转延迟+数据传输时间
是一种优化寻道时间的算法,基于如下前提,该算法才有意义:
当大量随机I/O请求到来时,磁头会前后指向不一样的磁道,致使寻道开销较大,使用一种优化的顺序减小磁头须要“走动的距离”,是调度算法须要考虑的
优先服务先来的I/O请求
优势:
缺点:
优先处理从当前磁臂移动距离最短的I/O请求
优势:
缺点:
扫描算法,也成电梯算法,先从一个方向处理全部I/O请求,到头以后从另外一个方向处理剩余I/O请求
这种算法缓解了SSTF中的饥饿状况,可是仍是会出现某个方向磁道边缘的I/O请求饥饿的状况
循环算法,从一个方向处理全部I/O请求直到磁道尽头,磁头立刻移动到另外一端(中间不处理请求),沿着这个方向继续处理全部请求
相比较SCAN,缓解了饥饿现象。保证磁道边缘的请求也能很快获得处理
C-SCAN会沿着一个方向处理I/O请求直到磁道尽头,C-LOOK的优化是沿着一个方向处理I/O请求直到该方向没有I/O请求,其余都同样
现代操做系统每每会结合这些算法进行使用,保证寻道时间短的同时,又不会出现请求饥饿的状况
因为访问磁盘的速度和访问内存的速度查了几个量级,因此须要使用磁盘缓存来缓解这个差别致使的瓶颈
这个缓存能够采用单缓存和双缓存
磁盘缓存须要一套置换算法来保证,常常用的扇区数据被缓存,少用的被置换到磁盘
这种算法结合了LRU和LFO的优势进行处理,短周期的以LRU为准,长周期的以LFO为准