写在前面:
找工做告一段落,期间经历了不少事情,也思考了许多问题,最后也收获了一些沉甸甸的东西 —— 成长和一些来自阿里、百度、京东(sp)、华为等厂的Offer。好在一切又回到正轨,接下来要好好总结一番才不枉这段经历,遂将此过程当中笔者的一些笔试/面试心得、干货发表出来,与众共享之。面试
进程和线程以及它们的区别
- 进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操做系统的并发;
- 线程是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的 实时性,实现进程内部的并发;
- 一个程序至少有一个进程,一个进程至少有一个线程,线程依赖于进程而存在;
- 进程在执行过程当中拥有独立的内存单元,而多个线程共享进程的内存。
进程间的通讯的几种方式
- 管道(pipe)及命名管道(named pipe):管道可用于具备亲缘关系的父子进程间的通讯,有名管道除了具备管道所具备的功能外,它还容许无亲缘关系进程间的通讯;
- 信号(signal):信号是一种比较复杂的通讯方式,用于通知接收进程某个事件已经发生;
- 消息队列:消息队列是消息的连接表,它克服了上两种通讯方式中信号量有限的缺点,具备写权限得进程能够按照必定得规则向消息队列中添加新信息;对消息队列有读权限得进程则能够从消息队列中读取信息;
- 共享内存:能够说这是最有用的进程间通讯方式。它使得多个进程能够访问同一块内存空间,不一样进程能够及时看到对方进程中对共享内存中数据得更新。这种方式须要依靠某种同步操做,如互斥锁和信号量等;
- 信号量:主要做为进程之间及同一种进程的不一样线程之间得同步和互斥手段;
- 套接字:这是一种更为通常得进程间通讯机制,它可用于网络中不一样机器之间的进程间通讯,应用很是普遍。
线程同步的方式
- 互斥量 Synchronized/Lock:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。由于互斥对象只有一个,因此能够保证公共资源不会被多个线程同时访问
- 信号量 Semphare:它容许同一时刻多个线程访问同一资源,可是须要控制同一时刻访问此资源的最大线程数量
- 事件(信号),Wait/Notify:经过通知操做的方式来保持多线程同步,还能够方便的实现多线程优先级的比较操做
什么是死锁?死锁产生的条件?
死锁的概念算法
在两个或者多个并发进程中,若是每一个进程持有某种资源而又等待其它进程释放它或它们如今保持着的资源,在未改变这种状态以前都不能向前推动,称这一组进程产生了死锁。通俗的讲,就是两个或多个进程无限期的阻塞、相互等待的一种状态。安全
死锁产生的四个必要条件网络
- 互斥:至少有一个资源必须属于非共享模式,即一次只能被一个进程使用;若其余申请使用该资源,那么申请进程必须等到该资源被释放为止;
- 占有并等待:一个进程必须占有至少一个资源,并等待另外一个资源,而该资源为其余进程所占有;
- 非抢占:进程不能被抢占,即资源只能被进程在完成任务后自愿释放
- 循环等待:若干进程之间造成一种头尾相接的环形等待资源关系
死锁的处理基本策略和经常使用方法多线程
解决死锁的基本方法主要有 预防死锁、避免死锁、检测死锁、解除死锁 、鸵鸟策略 等。并发
死锁预防分布式
死锁预防的基本思想是 只要确保死锁发生的四个必要条件中至少有一个不成立,就能预防死锁的发生,具体方法包括:性能
- 打破互斥条件:容许进程同时访问某些资源。可是,有些资源是不能被多个进程所共享的,这是由资源自己属性所决定的,所以,这种办法一般并没有实用价值。
- 打破占有并等待条件:能够实行资源预先分配策略(进程在运行前一次性向系统申请它所须要的所有资源,若所需所有资源得不到知足,则不分配任何资源,此进程暂不运行;只有当系统能知足当前进程所需的所有资源时,才一次性将所申请资源所有分配给该线程)或者只容许进程在没有占用资源时才能够申请资源(一个进程可申请一些资源并使用它们,可是在当前进程申请更多资源以前,它必须所有释放当前所占有的资源)。可是这种策略也存在一些缺点:在不少状况下,没法预知一个进程执行前所需的所有资源,由于进程是动态执行的,不可预知的;同时,会下降资源利用率,致使下降了进程的并发性。
- 打破非抢占条件:容许进程强行从占有者哪里夺取某些资源。也就是说,但一个进程占有了一部分资源,在其申请新的资源且得不到知足时,它必须释放全部占有的资源以便让其它线程使用。这种预防死锁的方式实现起来困难,会下降系统性能。
- 打破循环等待条件:实行资源有序分配策略。对全部资源排序编号,全部进程对资源的请求必须严格按资源序号递增的顺序提出,即只有占用了小号资源才能申请大号资源,这样就不回产生环路,预防死锁的发生。
死锁避免的基本思想操作系统
死锁避免的基本思想是动态地检测资源分配状态,以确保循环等待条件不成立,从而确保系统处于安全状态。所谓安全状态是指:若是系统能按某个顺序为每一个进程分配资源(不超过其最大值),那么系统状态是安全的,换句话说就是,若是存在一个安全序列,那么系统处于安全状态。资源分配图算法和银行家算法是两种经典的死锁避免的算法,其能够确保系统始终处于安全状态。其中,资源分配图算法应用场景为每种资源类型只有一个实例(申请边,分配边,需求边,不造成环才容许分配),而银行家算法应用于每种资源类型能够有多个实例的场景。线程
死锁解除
死锁解除的经常使用两种方法为进程终止和资源抢占。**所谓进程终止是指简单地终止一个或多个进程以打破循环等待,包括两种方式:终止全部死锁进程和一次只终止一个进程直到取消死锁循环为止;**所谓资源抢占是指从一个或多个死锁进程那里抢占一个或多个资源,此时必须考虑三个问题:
- 选择一个牺牲品
- 回滚:回滚到安全状态
- 饥饿(在代价因素中加上回滚次数,回滚的越多则越不可能继续被做为牺牲品,避免一个进程老是被回滚)
进程有哪几种状态?
- 就绪状态:进程已得到除处理机之外的所需资源,等待分配处理机资源;
- 运行状态:占用处理机资源运行,处于此状态的进程数小于等于CPU数;
- 阻塞状态: 进程等待某种条件,在条件知足以前没法执行;
线程有几种状态?
在 Java虚拟机 中,**线程从最初的建立到最终的消亡,要经历若干个状态:建立(new)、就绪(runnable/start)、运行(running)、阻塞(blocked)、等待(waiting)、时间等待(time waiting) 和 消亡(dead/terminated)。**在给定的时间点上,一个线程只能处于一种状态,各状态的含义以下图所示:
线程各状态之间的转换以下:
分页和分段有什么区别(内存管理)?
段式存储管理是一种符合用户视角的内存分配管理方案。**在段式存储管理中,将程序的地址空间划分为若干段(segment),如代码段,数据段,堆栈段;这样每一个进程有一个二维地址空间,相互独立,互不干扰。**段式管理的优势是:没有内碎片(由于段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(好比4k的段换5k的段,会产生1k的外碎片)
页式存储管理方案是一种用户视角内存与物理内存相分离的内存分配管理方案。在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为一样大小的帧,程序加载时,能够将任意一页放入内存中任意一个帧,这些帧没必要连续,从而实现了离散分离。页式存储管理的优势是:没有外碎片(由于页的大小固定),但会产生内碎片(一个页可能填充不满)。
二者的不一样点:
- 目的不一样:分页是因为系统管理的须要而不是用户的须要,它是信息的物理单位;分段的目的是为了能更好地知足用户的须要,它是信息的逻辑单位,它含有一组其意义相对完整的信息;
- 大小不一样:页的大小固定且由系统决定,而段的长度却不固定,由其所完成的功能决定;
- 地址空间不一样: 段向用户提供二维地址空间;页向用户提供的是一维地址空间;
- 信息共享:段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制;
- 内存碎片:页式存储管理的优势是没有外碎片(由于页的大小固定),但会产生内碎片(一个页可能填充不满);而段式管理的优势是没有内碎片(由于段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(好比4k的段换5k的段,会产生1k的外碎片)。
操做系统中进程调度策略有哪几种?
- FCFS(先来先服务,队列实现,非抢占的):先请求CPU的进程先分配到CPU
- SJF(最短做业优先调度算法):平均等待时间最短,但难以知道下一个CPU区间长度
- 优先级调度算法(能够是抢占的,也能够是非抢占的):优先级越高越先分配到CPU,相同优先级先到先服务,存在的主要问题是:低优先级进程无穷等待CPU,会致使无穷阻塞或饥饿;解决方案:老化
- 时间片轮转调度算法(可抢占的):队列中没有进程被分配超过一个时间片的CPU时间,除非它是惟一可运行的进程。若是进程的CPU区间超过了一个时间片,那么该进程就被抢占并放回就绪队列。
- 多级队列调度算法:将就绪队列分红多个独立的队列,每一个队列都有本身的调度算法,队列之间采用固定优先级抢占调度。其中,一个进程根据自身属性被永久地分配到一个队列中。
- 多级反馈队列调度算法:与多级队列调度算法相比,其容许进程在队列之间移动:若进程使用过多CPU时间,那么它会被转移到更低的优先级队列;在较低优先级队列等待时间过长的进程会被转移到更高优先级队列,以防止饥饿发生。
说一说进程同步有哪几种机制
原子操做、信号量机制、自旋锁管程、会合、分布式系统
什么是虚拟内存?
内存的发展历程
没有内存抽象(单进程,除去操做系统所用的内存以外,所有给用户程序使用) —> 有内存抽象(多进程,进程独立的地址空间,交换技术(内存大小不可能容纳下全部并发执行的进程)
)—> 连续内存分配(固定大小分区(多道程序的程度受限),可变分区(首次适应,最佳适应,最差适应),碎片) —> 不连续内存分配(分段,分页,段页式,虚拟内存)
虚拟内存
虚拟内存容许执行进程没必要彻底在内存中。虚拟内存的基本思想是:每一个进程拥有独立的地址空间,这个空间被分为大小相等的多个块,称为页(Page),每一个页都是一段连续的地址。这些页被映射到物理内存,但并非全部的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由硬件马上进行必要的映射;当程序引用到一部分不在物理内存中的地址空间时,由操做系统负责将缺失的部分装入物理内存并从新执行失败的命令。这样,**对于进程而言,逻辑上彷佛有很大的内存空间,实际上其中一部分对应物理内存上的一块(称为帧,一般页和帧大小相等),还有一些没加载在内存中的对应在硬盘上,**以下图所示。
注意,请求分页系统、请求分段系统和请求段页式系统都是针对虚拟内存的,经过请求实现内存与外存的信息置换。
由上图能够看出,虚拟内存实际上能够比物理内存大。当访问虚拟内存时,会访问MMU(内存管理单元)去匹配对应的物理地址(好比上图的0,1,2)。若是虚拟内存的页并不存在于物理内存中(如上图的3,4),会产生缺页中断,从磁盘中取得缺的页放入内存,若是内存已满,还会根据某种算法将磁盘中的页换出。
页面置换算法
- FIFO先进先出算法:在操做系统中常常被用到,好比做业调度(主要实现简单,很容易想到);
- LRU(Least recently use)最近最少使用算法:根据使用时间到如今的长短来判断;
- LFU(Least frequently use)最少使用次数算法:根据使用次数来判断;
- OPT(Optimal replacement)最优置换算法:理论的最优,理论;就是要保证置换出去的是再也不被使用的页,或者是在实际内存中最晚使用的算法。
虚拟内存的应用与优势
虚拟内存很适合在多道程序设计系统中使用,许多程序的片断同时保存在内存中。当一个程序等待它的一部分读入内存时,能够把CPU交给另外一个进程使用。虚拟内存的使用能够带来如下好处:
- 在内存中能够保留多个进程,系统并发度提升
- 解除了用户与内存之间的紧密约束,进程能够比内存的所有空间还大
颠簸
颠簸本质上是指频繁的页调度行为,具体来说,进程发生缺页中断,这时,必须置换某一页。然而,其余全部的页都在使用,它置换一个页,但又马上再次须要这个页。所以,会不断产生缺页中断,致使整个系统的效率急剧降低,这种现象称为颠簸(抖动)。
内存颠簸的解决策略包括:
- 若是是由于页面替换策略失误,能够修改替换算法来解决这个问题;
- 若是是由于运行的程序太多,形成程序没法同时将全部频繁访问的页面调入内存,则要下降多道程序的数量;
- 不然,还剩下两个办法:终止该进程或增长物理内存容量。
局部性原理
- 时间上的局部性:最近被访问的页在不久的未来还会被访问;
- 空间上的局部性:内存中被访问的页周围的页也极可能被访问。
END
喜欢的朋友记得点点赞和关注,支持下笔者,谢谢啦