参考资料:
[1]. 程序编译的四个过程
[2]. 怎样通俗的理解操作系统中内存管理分页和分段?
[3]. 一句话+一张图说清楚——银行家算法
[4]. 为什么校招面试中“线程与进程的区别”老是被问到?我该如何回答?
磁盘空闲空间管理
内存怎么分配
内存碎片解决办法
内存管理分段和分页
直接使用物理内存地址的局限,1、地址空间不隔离,2、程序运行时候的地址不确定,3、内存使用率低下。
系统如何提高并发性?
死锁
简单说,各自持有对方的锁,并且想要对方的锁。
(一)互斥条件:一个资源一次只能被一个进程访问。即某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占 有。这种独占资源如CD-ROM驱动器,打印机等等,必须在占有该资源的进程主动释放它之后,其它进程才能占有该资源。这是由资源本身的属性所决定的。
(二)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。进程至少已经占有一个资源,但又申请新的资源;由于该资源已被另外进程占有,此时该进程阻塞;但是,它在等待新资源之时,仍继续占用已占有的资源。
(三)不剥夺条件:进程已经获得的资源,在未使用完之前不能强行剥夺,而只能由该资源的占有者进程自行释放。
(四)循环等待条件:若干资源形成一种头尾相接的循环等待资源关系。
解决死锁
-
预防死锁
资源一次性分配:破坏请求和保持条件。
可剥夺资源:当进程新申请的资源不满足时,释放已经分配的资源。破坏不可剥夺条件。 在使用某些资源,比如打印机时,当强制剥夺已分配资源的时候,会导致打印机资源打印的信息不连续的问题。
资源有序分配:系统给进程编号,按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。 -
避免死锁
银行家算法:分配资源前先评估风险,会不会在分配后导致死锁。即分配给一个进程资源的时候,该进程能否全部返还占用的资源。 -
检测死锁
建立资源分配表和进程等待表。 -
解除死锁
从其他进程强制剥夺资源给死锁进程。
可以直接撤销死锁进程,或撤销代价最小的进程。
银行家算法
用来预防死锁,每次分配前计算,先分配给可以分配的线程,然后依次查看某个线程是否可以在分配之后进行资源回收,
内部碎片和外部碎片的区别
一般讲的内存碎片是:外部碎片。
内部碎片是已经被分配出去的的内存空间大于请求所需的内存空间。
外部碎片是指还没有分配出去,但是由于大小太小而无法分配给申请空间的新进程的内存空间空闲块。
程序编译的四个阶段
预处理->编译->汇编->链接
预处理:处理比如#include<studio.h>,得到完整的文件,结果后缀为.i
编译:转化为汇编,结果后缀为.s
汇编:转化为机器语言指令,结果后缀为.o
链接:由链接器将代码在执行过程用到的其他目标代码和库文件链接成为一个可执行程序也就是目标程序,链接主要完成了重定位,比如a.o是从0100,b.0也是从0200,链接的时候把这些链接成一个文件,假如a在前,b在后,那么b的地址就编程101~300。
- 静态链接
在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中,因此对应的链接方式称为静态链接。
- 静态库对函数库的链接是放在编译时期完成的。
- 程序在运行时与函数库再无瓜葛,移植方便。
-
浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
为什么需要动态库,其实也是静态库的特点导致,空间浪费是静态库的一个问题。另一个问题是静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
动态链接:
动态库特点总结:
动态库把对一些库函数的链接载入推迟到程序运行的时期。
可以实现进程之间的资源共享。(因此动态库也称为共享库)
将一些程序升级变得简单。
甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。
动态链接缺点:
(1)当系统中多个应用程序都用了一个动态链接库,但是要求的版本不同,这时动态链接库之间就会相互干扰,容易出现dll地狱的问题。
(2)性能开销。动态链接库为了做到“共享代码,但是不共享数据”,引入了不小的开销,调用动态链接库中的函数,需要好几次间接内存访问才能走到函数入口,全局数据也是。
- 形成逻辑地址的阶段
链接
内存如何寻址?
分页:有两次内存访问,先访问页表,页表的页表项是逻辑页号和物理页号的映射,得到物理页号后,再实际进行内存访问。分段也是差不多的,不过是段表。
进程之间通信方法有哪些?
管道是一种半双工的通信方式,数据只能单项流动,并且只能在具有亲缘关系的进程间流动,进程的亲缘关系通常是父子进程
命名管道也是半双工的通信方式,它允许无亲缘关系的进程间进行通信
信号量是一个计数器,用来控制多个进程对资源的访问,它通常作为一种锁机制。
消息队列是消息的链表,存放在内核中并由消息队列标识符标识。
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存就是映射一段能被其它进程访问的内存,这段共享内存由一个进程创建,但是多个进程可以访问。
进程间共享内存和消息队列有何异同?
几种通信方式的特点
管道:速度慢,容量有限
消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题。
信号量:不能传递复杂消息,只能用来同步
共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了一块内存的。
为什么进程通信需要内核的东西?
因为每个进程是独立的地址,无法访问别的进程的地址。
为什么一个进程的线程可以共享内存,然后进程和进程之间的内存是独立的呢?
每个进程都有他自己在页表所对应的页表项,只能映射到它自己的内存。
分页和分段有什么区别
段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的 ;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的。
段的大小不固定,有它所完成的功能决定;页大大小固定,由系统决定
段向用户提供二维地址空间;页向用户提供的是一维地址空间
段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制。
分页管理方式是从计算机的角度考虑设计的,以提高内存的利用率,提升计算机的性能,且分页通过硬件机制实现,对用户完全透明;而分段管理方式的提出则是考虑了用户和程序员,以满足方便编程、信息保护和共享、动态增长及动态链接等多方面的需要。
分页和分段都是一种非连续分配管理方式,不连续分配的好处是不用一次性分配一段连续的内存。连续分配管理一种是固定分区,一种是动态分区,固定分区在分配之前就已经把内存分为固定的大小(但是大小可能不同),这个时候会产生内存碎片,动态分区会产生外部碎片,这个时候不连续分配的好处就出来了,通过将内存切分为大小相同且固定的块,可以减少内存碎片。分页也会产生内部碎片,发生在最后一次分配的时候,平均一个线程产生半个页大小的内存碎片,页比固定分配的块小很多,因此产生的碎片也相对比较小。
操作系统中进程调度策略有哪几种?
- 先来先服务FCFS算法
- 短作业有限(SJF)算法
- 优先级调度算法
- 高响应比优先
- 时间片轮转
- 多级反馈队列
管程(monitor)
也就是java里面的sychronized
采用( )不会产生内部碎片(“内零头”)
A、分页式存储管理 B、分段式存储管理
C、固定分区式存储管理 D、段页式存储管理
B,还有连续分配的动态分区分配也不会产生内部碎片。
段页式管理每取一数据,要访问()次内存。
A、1 B、2 C、3 D、4
B,段表,页表,内存
虚拟内存空间是什么,为什么要有虚拟内存空间。
扩展内存,通过内存置换来实现
页面置换算法(操作系统的页面置换算法,详细讲了一下)
FIFO先进先出算法:在操作系统中经常被用到,比如作业调度(主要实现简单,很容易想到);
LRU(Least recently use)最近最少使用算法:根据使用时间到现在的长短来判断;
LFU(Least frequently use)最少使用次数算法:根据使用次数来判断;
OPT(Optimal replacement)最优置换算法:理论的最优,理论;就是要保证置换出去的是不再被使用的页,或者是在实际内存中最晚使用的算法。
内存连续分配
首次适应(First Fit)算法:空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区。
最佳适应(Best Fit)算法:空闲分区按容量递增形成分区链,找到第一个能满足要求的空闲分区。
最坏适应(Worst Fit)算法:又称最大适应(Largest Fit)算法,空闲分区以容量递减的次序链接。找到第一个能满足要求的空闲分区,也就是挑选出最大的分区。
网友评论