文章目录
- 一、请你说一下进程与线程的概念,以及为什么要有进程线程,其中有什么区别?
- 二、请你说一下进程和线程间的通信?
- 三、请你说一说虚拟内存?
- 四、请你说一说操作系统中的程序的内存结构
- 五、请你说一说操作系统中的缺页中断
- 六、请你说一说死锁的发生条件及如何解决死锁
- 七、什么是银行家算法?
- 八、请你讲述一下操作系统系统中锁?
- 九、请你说一说内存溢出和内存泄露?
- 十、请你说说Java中的内存泄露
- 十一、请你来说一说协程
- 十二、系统调用是什么?你用过哪些系统调用?
- 十三、说一说僵尸进程、孤儿进程、守护进程
- 十三、说一说你常用的Linux命令
- 十四、操作系统中的进程调度算法
- 十五、你怎么理解操作系统里的内存碎片,有什么解决办法?
- 十六、通常系统CPU比较高是什么原因?
一、请你说一下进程与线程的概念,以及为什么要有进程线程,其中有什么区别?
1 、 基 本 概 念 \color{green}{1、基本概念} 1、基本概念
- 进程是对运行程序的封装,是系统进行资源调度和分配的基本单位,实现了操作系统的并发。
- 线程是进程的子任务,是CPU调度和分派的基本单位,实现进程内部的并发。
2 、 区 别 \color{green}{2、区别} 2、区别
- 一个线程是能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程依赖于进程而存在。
- 进程在执行过程中拥有独立的内存单元,而多个线程共享进程的内存。资源分配给进程,同一进程的所有线程共享该进程的所有资源。同一进程中的多个线程共享代码段(代码和常量)、数据段(全局变量和静态变量)、扩展堆(堆存储)。但是每个线程拥有自己的栈段,又叫运行时段,用来存储所有局部变量和临时变量。
- 进程切换的开销远大于线程切换的开销。在进行进程切换时,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置;而线程切换只须保存和设置少量寄存器的内容,并不涉及存储器管理方面的操作。
二、请你说一下进程和线程间的通信?
进程间通信方式
1 、 管 道 \color{green}{1、管道} 1、管道
- 无名管道:它是半双工(数据只能在一个方向上流动);具有固定的读端和写端,并且只能用于具有亲缘关系(父子,兄弟)的进程之间的通信。
- 有名管道:可以在无关的进程之间交换数据。
2 、 系 统 I P C \color{green}{2、系统IPC} 2、系统IPC
- 消息队列:是消息的链接表,存放在内核中,一个消息队列有一个标识符(队列ID)来标记;消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点。消息队列独立于发送与接收进程,进程终止时,消息队列及其内容并不会被删除;并且可以实现消息的随机查询,不一定要以先进先出的次序读取,也可以按消息的类型读取。
- 信号量semaphore:是一个计数器,可以用来控制多个进程对共享资源的访问,用于实现进程间的互斥与同步,若要在进程间传递数据需要结合共享内存。
- 信号signal:信号是一种比较复杂的通信方式,用于通知接受进程某个事件已经发生。
- 共享内存:它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新(需要互斥锁或信号量的支持)。信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
3 、 套 接 字 s o c k e t \color{green}{3、套接字socket} 3、套接字socket
- 可用于不同主机之间的进程通信。
线程间通信方式
1
、
临
界
区
\color{green}{1、临界区}
1、临界区:通过多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
2
、
互
斥
量
S
y
n
c
h
r
o
n
i
z
e
d
/
L
o
c
k
\color{green}{2、互斥量Synchronized/Lock}
2、互斥量Synchronized/Lock:采用互斥锁对象机制,只有拿到这个锁的线程才能访问公共资源的权限。
3
、
信
号
量
\color{green}{3、信号量}
3、信号量:它允许多个线程在同一时刻去访问同一个资源,但一般需要限制同一时刻访问此资源的最大线程数。
4
、
事
件
(
信
号
)
W
a
i
t
/
N
o
t
i
f
y
\color{green}{4、事件(信号)Wait/Notify}
4、事件(信号)Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。
三、请你说一说虚拟内存?
1 、 为 什 么 会 有 虚 拟 内 存 ? \color{green}{1、为什么会有虚拟内存?} 1、为什么会有虚拟内存?
虚拟内存别称虚拟存储器(Virtual Memory)。电脑中所运行的程序均需经由内存执行,若执行的程序占用内存很大或很多,则会导致内存消耗殆尽。为解决该问题,Windows中运用了虚拟内存技术,即匀出一部分硬盘空间来充当内存使用。当内存耗尽时,电脑就会自动调用硬盘来充当内存,以缓解内存的紧张。若计算机运行程序或操作所需的随机存储器(RAM)不足时,则 Windows 会用虚拟存储器进行补偿。它将计算机的RAM和硬盘上的临时空间组合。当RAM运行速率缓慢时,它便将数据从RAM移动到称为“分页文件”的空间中。将数据移入分页文件可释放RAM,以便完成工作。 一般而言,计算机的RAM容量越大,程序运行得越快。若计算机的速率由于RAM可用空间匮乏而减缓,则可尝试通过增加虚拟内存来进行补偿。但是,计算机从RAM读取数据的速率要比从硬盘读取数据的速率快,因而扩增RAM容量(可加内存条)是最佳选择。
2 、 什 么 是 虚 拟 地 址 空 间 ? \color{green}{2、什么是虚拟地址空间?} 2、什么是虚拟地址空间?
虚拟地址空间又叫虚拟内存,是计算机系统内存管理的一种技术,它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分割成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型系统的编写变得更容易,对真正的物理内存(RAM)的使用功能也更有效率。
2 、 虚 拟 内 存 的 好 处 ? \color{green}{2、虚拟内存的好处?} 2、虚拟内存的好处?
- 内存保护:每个进程运行在各自的虚拟内存地址空间,互相不能干扰对方虚拟内存还对特定的内存地址提供写保护,可以防止代码或主句被恶意篡改。
- 公平内存分配:采用了虚拟内存之后,每个进程都相当于有同样大小的虚拟空间。
- 当进程通信时,可采用虚拟共享的方式实现。
- 节省内存:当不同的进程使用相同的代码时,比如库文件中的代码,物理内存中只需要存储一份这样的代码,不同的进程只需要把自己的虚拟内存映射进去就可以了,节省内存。
- 可以利用碎片化空间:在程序需要分配连续的内存空间的时候,只需要在虚拟内存空间分配连续空间,而不需要实际物理内存的连续空间,可以利用碎片。
3 、 虚 拟 内 存 和 物 理 内 存 的 区 别 ? \color{green}{3、虚拟内存和物理内存的区别?} 3、虚拟内存和物理内存的区别?
(1)作用不同:
- 物理内存:是在计算机运行时为操作系统和各种程序提供临时存储。
- 虚拟内存: 使得应用程序认为拥有连续的可用的内存。
(2)特点不同
- 物理内存:直接决定了电脑同时运行多少个程序的流畅度,会对系统的虚拟内存限制有影响。
虚拟内存的大小=物理内存容量+所有页面文件的最大容量。- 虚拟内存:被分割成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
(3)主体不同
- 物理内存:指通过物理内存条而获得的内存空间。
- 虚拟内存:是计算机系统内存管理的一种技术。是操作系统作为内存而使用的一部分硬盘空间。
四、请你说一说操作系统中的程序的内存结构
- 堆 \color{green}{堆} 堆:用于动态分配内存,由程序员申请分配和释放。堆是从低地址向高地址为增长,采用链式存储结构。当申请堆空间时库函数是按照一定的算法搜索可用的足够大的空间,因此堆的效率比栈要低的多。
- 栈 \color{green}{栈} 栈:有编译器自动释放,存放函数的参数值、局部变量等。每当一个函数被调用时,该函数的返回类型和一些调用的信息被存放到栈中。然后这个被调用的函数再为他的自动变量和临时变量在栈上分配空间。每调用一个函数一个新的栈就会被使用。
- 数 据 段 \color{green}{数据段} 数据段:存放程序中已初始化的全局变量的一块内存区域,数据段也属于静态内存分配。
- 代 码 段 \color{green}{代码段} 代码段:存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域属于只读,在代码段中,也有可能包含一些只读的常数变量。
- B B S 未 初 始 化 数 据 区 \color{green}{BBS 未初始化数据区} BBS未初始化数据区:通常用来存储程序中未初始化的全局变量和静态变量的一块内存区域。BSS段属于静态分配,程序结束后静态变量资源由系统自动释放。
五、请你说一说操作系统中的缺页中断
1
、
什
么
是
缺
页
中
断
?
\color{green}{1、什么是缺页中断?}
1、什么是缺页中断?
简单来说:缺页中断就是要访问的页不在主存,需要操作系统将其调入主存后再进行访问。
在请求分页系统中,可以通过查询页表中的状态位来确定所要访问的页面是否存在与内存中,每当所要访问的页面不在内存时,会产生一次缺页中断,此时操作系统会根据页表中的外存地址在外存中找到所缺的一页,将其调入内存。
2 、 缺 页 中 断 的 处 理 步 骤 ? \color{green}{2、缺页中断的处理步骤?} 2、缺页中断的处理步骤?
- 1、保护CPU现场
- 2、分析中断原因
- 3、转入缺页中断处理程序进行处理
- 4、恢复CPU现场,继续执行
3 、 常 见 的 页 面 置 换 算 法 \color{green}{3、常见的页面置换算法} 3、常见的页面置换算法
当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。
-
1、最佳置换算法(OPT):从主存中移除永远不再需要的页面或者未来最长时间内不再被访问的页面,该算法保证了可以获得最低缺页率,但无法预知未来页面的使用情况,因此目前无法实现,但常用来评价其他算法。
-
2、先进先出置换算法(FIFO):当需要淘汰一个页面时,总是选择驻留主存时间最长的页面进行淘汰,即先进入主存的页面先淘汰。其理由是:最早调入主存的页面不再被使用的可能性最大。
-
3、最近最久未使用算法(LRU):该算法以过去预测未来,选择之前最长时间未使用的页面置换。但是由于利用“过去”作为“未来”的近似这一做法并非完全可靠,因此有时会造成缺页率非常高,效率很低。
-
4、最不常用页面置换算法(NFU):用一个软件模拟LRU,该算法将每个页面与一个软件计数器相关联。计数器的初值为0,每次时钟中断时,由操作系统扫描内存中所有的页面,将每个页面的R位(0或1)加到它的计数器上,这个计数器大体上跟踪了各个页面被访问的频繁程度。当发生缺页中断时,则置换计数器值最小的页面。
六、请你说一说死锁的发生条件及如何解决死锁
死锁是指两个或两个以上进程在执行过程中,因争夺资源而造成的互相等待的现象,死锁的发生有四个必要条件。
- 互斥条件:进程对所分配到的资源不允许其他进程访问,若其他进程访问该资源,只能等待,知道占用该资源的进程使用完成后释放该资源。
- 请求和保持条件:进程获得一定的资源后,又对其他资源发出请求,但是该资源可能被其他进程占有,此时请求阻塞,但该进程不会释放自己已占有的资源。
- 不可剥夺条件:进程已获得的资源,在未使用完成之前,不可被剥夺,只能在使用后自己释放。
- 环路等待条件:进程发生死锁后,必然存在一个进程—>资源之间的环形链。
解决死锁的方式即破坏上述四个条件之一,方法如下:
1、资源一次性分配,从而剥夺请求和保持条件
2、可剥夺资源:即当进程新的资源未得到满足时,释放已占有的资源,从而破坏不可剥夺的条件。
3、资源有序分配法:系统给每类资源赋予一个序号,每个进程按编号递增的请求资源,释放则相反,从而破坏环路等待的条件。
七、什么是银行家算法?
允许进程动态地申请资源,系统在每次实施资源分配之前,先计算资源分配的安全性,若此次资源分配安全(即资源分配周,系统能按某种顺序来为每个进程分配其所需的资源,直至最大需求,使每个进程都可以顺利完成),便将资源分配给进程,否则不分配资源,让进程等待。
银行家算法是避免死锁的一种重要方法。操作系统按照指定规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按照当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请的资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源,若没有超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配。
八、请你讲述一下操作系统系统中锁?
1
、
互
斥
锁
\color{green}{1、互斥锁}
1、互斥锁
用于保证在任何时刻,都只能有一个线程访问该对象。当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒。
2 、 读 写 锁 \color{green}{2、读写锁} 2、读写锁
- 处于读操作时,可以**允许多个线程同时获得读操作,但是同一时刻只能有一个线程可以获得写锁,**其他获取写锁失败的线程都会进入睡眠状态,知道写锁释放时被唤醒。
- 写锁会阻塞其他读写锁,当有一个线程获得写锁在写时,读锁也不能被其他线程获取。
读锁会阻塞写,但不会阻塞读
写锁会把读和写都阻塞
3
、
自
旋
锁
\color{green}{3、自旋锁}
3、自旋锁
在任何时刻同样只能有一个线程访问对象,但是当获取锁操作失败时,不会进入睡眠,而是会在原地自旋,一直尝试获取锁,直到获取到。这样节省了线程从睡眠状态到唤醒期间的消耗,在枷锁时间短暂的环境下会极大的提高效率。但如果枷锁时间过长,则会非常浪费CPU资源。
九、请你说一说内存溢出和内存泄露?
1
、
内
存
溢
出
\color{green}{1、内存溢出}
1、内存溢出
指程序申请内存时,没有足够的内存供申请者使用。内存溢出就是你要的内存空间超过了系统实际分配给你的空间,此时系统相当于没法满足你的需求,就会报内存溢出的错误。
内存溢出原因:
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据。
- 集合类中有对对象的引用,使用完后未清空,使得不能回收。
- 代码中存在死循环或循环产生过多重复的对象实体。
- 使用第三方软件中的BUG
- 启动参数内存值设定过小
2 、 内 存 泄 露 \color{green}{2、内存泄露} 2、内存泄露
内存泄露是由于疏忽或错误造成了程序未能释放掉不再使用内存的情况,内存泄露并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
- 堆内存泄露:对内存指的是程序运行中根据需要分配通过malloc,realloc,new等从堆中分配的一块内存,完成后必须通过调用对应的free或者delete删掉。如果程序的设计的错误导致这部分内存没有被释放,那么次后这块内存将不会被使用。就是发生内存溢出。
- 系统资源泄露:主要指程序使用系统分配的资源比如 Bitmap,handle ,SOCKET等没有使用相应的函数释放掉,导致系统资源的浪费,严重可导致系统效能降低,系统运行不稳定。
3 、 L i n u x 下 检 测 内 存 泄 露 \color{green}{3、Linux下检测内存泄露} 3、Linux下检测内存泄露
- valgrind:程序检测工具
- mtrace
十、请你说说Java中的内存泄露
由于Java的JVM引入了垃圾回收机制,垃圾回收器会自动回收不再使用的对象,JVM回收对象的本质是判断一个对象是否还被引用。那么对于这种情况,由于代码的实现不同就会出现很多种内存泄露问题(让JVM误以为此对象还在引用中,无法回收,造成内存泄露)。
1 、 常 见 的 内 存 泄 露 问 题 \color{green}{1、常见的内存泄露问题} 1、常见的内存泄露问题
- 长生命周期的对象持有短生命周期的引用,就很有可能出现内存泄露
public class Test {
Object object;
public void test(){
object = new Object();
//...其他代码
}
}
# 在这个例子中,test方法结束后,创建出来的object所占用的内存不会马上被认为是可以释放,就有可能发生内存泄露,
- 各种连接,如数据库连接、网络连接和IO连接等,没有显示调用close关闭,不被GC回收会导致内存泄露
- 单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被JVM正常回收,导致内存泄露。
2 、 如 何 避 免 内 存 泄 露 的 发 生 \color{green}{2、如何避免内存泄露的发生} 2、如何避免内存泄露的发生
- 尽量减少使用静态变量,类的静态变量的生命周期和类时同步的。
- 声明对象引用之前,明确内存对象的有效作用域,尽量减少对象的作用域,将类的成员变量改写为方法内的局部变量。
- 减少长声明周期的对象持有短生命周期的引用。
- 使用StringBuilder和StringBuffer进行字符串连接,String字符串代表的是不可变的字符串,如果使用多个String对象进行字符串连接运算,在运行时可能产生大量临时字符串,这些字符串会保存在内存中导致程序性能下降。
- 对于不需要的对象需要手动设置null值,不管GC何时开始清理。
- 各种连接操作,用完之后应该关闭。
十一、请你来说一说协程
- 协程:是一种比线程更加轻量级的存在,正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。协程不是操作系统内核所管理,而是完全由程序控制(即用户态执行),因此,不会线程切换那样消耗资源。
- 协程不是进程也不是线程,而是一种特殊的函数,这个函数既可以在某个地方挂起,并且可以重新在挂起处继续运行。一个线程的多个协程的运行时串行的,当一个协程运行时,其他线程必须挂起。
协程在在子程序内部是可中断的,然后转而执行别的的子程序,在适当的时候再返回来接着执行。
协程和线程一样共享堆,不共享栈,协程有程序员在协程的代码里显示调度。
一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的·,在线程里面可以开启协程,让程序在特定的时间内运行。
协程的优势?
- 协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准使用多CPU的能力。
- 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
十二、系统调用是什么?你用过哪些系统调用?
1 、 概 念 \color{green}{1、概念} 1、概念
系统调用:系统调用是操作系统提供给用户的一种服务,程序设计人员在编写程序的时候可以用来请求操作系统的服务。
常见的系统调用:文件相关操作、系统控制、进程控制。
2 、 内 核 态 和 用 户 态 \color{green}{2、内核态和用户态} 2、内核态和用户态
为什么要有内核态和用户态?
有时需要限制不同程序之间的访问能力,防止他们获取别的程序的内存数据,或者获取外围设备的数据,并发送到网络,CPU划分出两个权限等级—用户态和内核态。
用户态:也叫普通态,cpu访问资源有限。
- cpu访问资源有限
- 程序的可靠性、安全性要求低
内核态:cpu可以访问计算机的任何资源
- cpu可以访问任何资源
- 程序的可靠性、安全性要求高
用户态如何切换到内核态?
- 系统调用:对文件进行写操作,open和write都是系统调用。
- 外围设备中断
- 异常
3 、 系 统 调 用 工 作 流 程 \color{green}{3、系统调用工作流程} 3、系统调用工作流程
所有用户程序都是运行在用户态的,但是有时候程序需要做一些内核态的事情,例如从硬盘读取数据,或者从键盘获取输入等,而唯一可以做这些事情的就是操作系统,所以此时程序就需要操作系统请求以程序的名义来执行这些操作。
系统调用的工作流程:
1、用户态将一些数据值访问在寄存器中,或者使用参数创建一个堆栈,以此表明需要操作系统提供的服务。
2、用户态程序执行陷阱指令。
3、CPU切换到内核态,并跳到位于内存指定位置的指令,这些指令是操作系统的一部分,他们具有内存保护,不可被用户态程序访问。
这些指令称之为陷阱或者系统调用处理器,他们会读取程序放入内存的数据参数,并执行程序请求的服务。
4、系统调用完成后,操作系统会重置CPU为用户态并返回系统调用的结果
十三、说一说僵尸进程、孤儿进程、守护进程
在Linux中,正常情况下,子进程是通过父进程创建的,子进程再创建新的进程。子进程的结束和父进程的运行时一个异步过程,即父进程永远无法预测子进程到底什么时候结束。当一个进程在完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。
1
、
孤
儿
进
程
\color{green}{1、孤儿进程}
1、孤儿进程
一个父进程退出,而它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并有init进程对他们完成状态收集工作。
2
、
僵
尸
进
程
\color{green}{2、僵尸进程}
2、僵尸进程
一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称之为僵尸进程。
查看:利用ps命令,可以看到有标记为Z的进程就是僵尸进程。
清除:杀死父进程,父进程死后,僵尸进程成为孤儿进程,过继给1号进程init。
3
、
守
护
进
程
\color{green}{3、守护进程}
3、守护进程
守护进程就是在后台运行,不在任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户运行,并能处理一些系统级的任务。
十三、说一说你常用的Linux命令
1、ps -ef|grep xxx:查看某个进程的进程号
2、kill:终止一个进程
3、ifconfig:查看所有网络接口及其状态
4、lsof -i:端口号:查看某个端口是否被占用
5、free:显示系统当前内存的使用情况,包括已用内存、可用内存和交换内存。
6、top:查看当前系统中占用资源最多的一些进程
7、find:查找指定文件名的文件
8、df:显示文件系统的磁盘使用情况,默认情况下df -k将以字节为单位输出磁盘的使用量。
十四、操作系统中的进程调度算法
- 周转时间:指作业从提交系统开始,直到作业完成为止的时间间隔。
- 带权周转时间:是指作业周转时间与作业实际运行服务时间的比值。平均周转时间和平均周转时间和平均带权周转时间是衡量批处理操作系统调度算法的重要原则。
- 服务时间:作业需要运行的时间
- 完成时间 = 开始时间 + 服务时间
- 等待时间 = 开始时间 - 提交时间
- 周转时间 = 完成时间 - 提交时间
- 带权周转时间 = 周转时间 / 服务时间
- 响应比 = (等待时间 + 服务时间) / 服务时间 = 等待时间/服务时间 + 1
先来先服务
是最简单的调度算法,可以用于作业调度和进程调度,按照作业进入系统后备作业队列的先后次序来挑选作业,加入就绪队列,等待执行。
先来先服务调度算法是非抢占式的,易于实现,效率不高,性能不好,有利于长作业(CPU繁忙型)而不利于短作业(I/O繁忙型)。
短作业优先
短作业优先调度算法用于进程调度时又被称为短进程优先调度算法,该算法既可以用户作业调度,又可以用户进程调度。
在作业调度中,该算法每次从后备作业队列中挑选估计服务时间最短的一个或几个作业,将他们调入内存,分配必要的资源,创建进程并放入就绪队列。在进程调度中的原理类似。
短作业优先是非抢占式的,优先照顾短作业,具有很好的性能,降低平均等待时间,提高吞吐量,但是不利于长作业,长作业可能一直处于等待状态,出现饥饿现象;完全为考虑作业的优先紧迫程度,不能用于实时系统。
最短剩余时间优先
短作业优先是非抢占式的,用户抢占式调度系统时,对应的算法称为最短剩余时间优先调度算法。
该算法首先按照作业的服务时间挑选最短的作业运行,在该作业运行期间,一旦有新作业达到系统,并且该新作业的服务时间比当前运行作业的剩余服务时间短,则发生抢占;否则当前作业继续运行。该算法确保一旦新的短作业或短进程进入系统,能够很快得到处理。
由于频繁的抢占和进程切换,系统开销大,该算法实现代价高,一般用户实时系统。
高响应比优先
高响应比优先调度算法是非抢占式的,主要用于作业调度。
每次作业调度时,先计算后备作业队列中每个作业的响应比,挑选最高的作业投入系统。
该算法介于先来先服务和短作业优先两种算法之间,但是每次需要计算每个作业的响应比,增加系统开销。
时间片轮转
系统将CPU处理时间划分为若干个时间片(q),进程按照到达先后顺序排列,每次调度选择队首的进程,执行完1个时间片q后,计时器发出时钟中断请求,该进程移至队尾。以后每次调度都是如此。该算法能在给定的时间内响应所有用户的请求,达到分时系统的目的。
其性能主要取决于时间片q的大小,q太大,则所有的进程在1个时间片完成。
该算法简单有效,常用于分时系统,但不利于I/O频繁的,由于这种进程用不完一个时间片,就因为等待IO操作而被阻塞,当IO操作结束后,只能插入到就绪队列的末尾,等待下一轮调度。
十五、你怎么理解操作系统里的内存碎片,有什么解决办法?
内存碎片分为:内部碎片和外部碎片。
内部碎片和外部碎片的最明显区别就是内部碎片能明确指出这部分内存是属于哪个进程的,而外部碎片不属于任何进程。
内部碎片:是指已经分配给某个进程,但是该进程却使用不到的内存空间,只有当该进程运行完毕后才能释放这块内存空间给其他进程使用。
外部碎片:指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配申请内存空间的新进程的内存空闲区域。
外部碎片是处于任何已分配区域页面外部的空闲存储块。这些存储块的总和可以满足当前申请的长度要求,但是由于它们的地址不连续或其他原因,使得系统无法满足当前申请。
解决办法:
- 利用分页单元把一组非连续的空闲页框映射到连续的线性地址——非连续内存分配(段式、页式、段页式)
- 开发一种适当的技术来记录现存空闲的连续页框块的情况,以尽量为满足对小块的请求而分割大的空闲块——伙伴系统
伙伴系统
把所有的空闲页框分组为11个块链表,每个链表分别包含大小为1,2,4,8,16,32,64,128,256,512,1024个连续的页框,每个页框大小为4KB。每次进程申请内存时,就从比申请规模大的链表中拆出指定内存,将被拆解的块中的剩余部分再进行拆解并插入到指定链表中。
比如现在要申请一个256个页框(1M)的块。
- 在256个页框的链表中检查是否有一个空闲块,如果没有,查找下一个更大的块,如果有,请求满足。
- 在512个页框的链表中检查是否有一个空闲块,如果有,把512个页框的空闲块分为两份,第一份用户满足请求,第二份链接到256个页框的链表中。如果没有空闲块,继续寻找下一个更大的块。
非连续内存分配
非连续内存分配允许一个程序使用非连续的物理地址空间,即一个程序的逻辑地址空间被映射到到物理地址空间不同的块,每一个块内部是连续的,但块与块之间可以不连续。其核心目标是提高内存利用率和管理灵活性,并允许代码和数据的共享。
1、段式
操作系统为应用程序设置段表,段表维护了每一个段的基址和长度,用段号(本质就是段表的索引)就能查找到对应的段基址和长度。内存访问顺序如下:CPU计算的时候取出逻辑地址(段号, 偏移);用段号去查找出对应的段基址和段长度;判断逻辑地址的偏移和段长度的大小关系,如果偏移大于段长度,那么直接报内存异常;通过段基址加上逻辑地址便宜,就找到了物理内存的实际地址。
2、页式
页式式比段式更细粒度的策略,对于页式存储管理,首先需要了解两个概念:页帧、页面。
页帧:又称物理页面,是指把物理空间划分为大小相同的基本分配单元,基本单元的大小为2的N次方。因此内存物理地址可以由二元祖(f, o)表示,其中f为帧号, o为帧内偏移,假设每一帧的大小为2的S次方,那么物理地址 = f *2 S + o.
页面:又称为逻辑页面,是指把逻辑地址空间划分为大小相同的基本分配单元。因此逻辑地址可以由二元祖(p, o)表示,其中p为页号, o为页内偏移,假设每一页的大小为2的S次方,那么逻辑地址 = p *2 S + o.在linux环境下,可以用shell命令 getconf PAGESIZE 来查看页面的大小。
为了方便,帧 与 页的基本大小相同,因此页内偏移 等于 帧内偏移; 但页号不等于帧号。因此只需要维护页号到帧号的映射关系就行了,这就是页表的作用。
每个进程都有一个页表,每个页面对应一个页表项,页表随进程的运行状态动态变化,页表基址寄存器(page table base register)记录页表的基址。由页表基址加上页号就能得到响应的页表项,页表项里面最重要的就是帧号信息,当然还有一些其他字段,如存在位、修改位等。
CPU计算的时候取出逻辑地址(页号, 偏移);用页号加上页表基址得到页表项,取出帧号;通过帧号和偏移,就找到了物理内存的实际地址。
页式存储管理的两个问题:
- 访问一个单元需要两次内存访问(先读页表项,再读数据),这是性能问题。
- 如果地址空间比较大,而页面的基本单元较小,那么一个页表的大小会很大,这个是额外空间消耗问题。
3、段页式
段式和页式各有优劣,段式存储在内存保护方面有优势,而页式存储在内存利用和优化转移后备存储(即虚拟存储)方面有优势。段页式是二者的集合,即在段式存储管理基础上给每个段加一级页表。这样没逻辑地址就变成了三元组(s,p,o),分别是段号、页号和页内偏移。
段页式存储管理,进程的段表项实际上存储的是该段的页表项,这样不同的段(属于不同的进程)可以指向同一个页表,这就可以共享段。
十六、通常系统CPU比较高是什么原因?
1、首先查看是哪些进程的CPU占用率最高
ps -aux --sort -pcpu | more
定位有问题的线程可以用如下命令
~~~shell
ps -mp pid -o THREAD,tid,time | more
2、查看JAVA进程的每个线程的CPU占用率
ps -Lp 5798 cu | more # 5798是查出来进程PID
3、追踪线程,查看负载过高的原因,使用JDK下的一个工具
jstack 5798 # 5798是PID
jstack -J-d64 -m 5798 # -j-d64指定64为系统
4、日志中,包含某条件的行数
find access_log.20160423.txt | xargs cat | grep .*helloworld.*|wc -l
例子说明:统计含"helloworld"字符串的总行数
5、日志中,不包含某条件的行数
find access_log.20160423.txt | xargs cat | grep -v .*helloworld.*|wc -l
例子说明:统计不含"helloworld"字符串的总行数
6、查找文件夹下,查找包含某一个字符串的文件
find <directory> -type f -name "*.c" | xargs grep "<strings>"
<directory>是你要找的文件夹;如果是当前文件夹可以省略
-type f 说明,只找文件
-name "*.c" 表示只找C语言写的代码,从而避免去查binary;也可以不写,表示找所有文件
<strings>是你要找的某个字符串