IOS面试:操作系统

2020-07-16  本文已影响0人  时光啊混蛋_97boy

原创:面试经验型文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容

目录

1、滴滴二面:进程间通信方式

IPC原理:Client进程向Server进程通信,是利用进程间可共享的内核内存空间来完成底层通信工作的。
IPC方式:包括管道( pipe )、信号 ( signal ) 、信号量( semophore ) 、消息队列( message queue ) 、共享内存( shared memory ) 、套接字( socket ) 。

管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。缺点是只能承载无格式字节流以及缓冲区大小受限。

信号 ( signal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。除了用于进程间通信外,进程还可以发送信号给进程本身。不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等。

信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。不适用于交换大批数据,而用于多线程之间的同步。常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

消息队列( message queue ) : 消息队列是消息的链表,存放在内核中并由消息队列标识符标识。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。缺点是信息复制两次,额外的CPU消耗。

共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。无须复制,共享缓冲区直接付附加到进程虚拟地址空间,速度快。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。缺点是进程间的同步问题操作系统无法实现。

套接字( socket ) : 更为一般的进程间通信机制,可用于不同机器之间进程间或跨网络的通信。缺点是传输效率低。

iOS 的每一个 app 都是一个独立的进程,它没有 Android那种比较开放的多进程通讯能力,甚至 AppExtension (如通知中心插件)之间都不能有一种非常直接的通讯方式,当然不是说iOS没有IPC 技术,mach 内核提供了诸如处理器调度、IPC (进程间通信)等非常少量的基础服务。Android 则不太一样,Android apps 基本上都需要各式各样的IPC需求,甚至启动一个Activity也需要用到IPC

2、什么是缓冲区溢出?危害是什么?原因是什么?

缓冲区溢出是指计算机向缓冲区填充数据时超出缓冲区本身的容量,溢出的数据覆盖在合法数据上。
危害:程序崩溃,导致拒绝服务。跳转并且执行一段恶意代码。
原因:未检出用户非法输入

3、进程有哪几种状态?

就绪状态:进程已获得除处理器以外的所需资源,等待分配处理机资源
运行状态:占用处理机资源正在执行,处于此状态的进程小于等于处理器个数
阻塞状态:进程等待某种条件,在条件满足之前无法执行

4、分页与分段的区别?

相似之处:都采用离散分配方式,且都要通过地址映射机制来实现地址转换

不同之处:

5、操作系统中进程调度策略?

FCFS(先来先服务)
优先级
时间片轮转
多级反馈

6、页面置换算法

作用

缓冲池是数据库最终的概念,数据库可以将一部分数据页放在内存中形成缓冲池,当需要一个数据页时,首先检查内存中的缓冲池是否有这个页面,如果有则直接命中返回,没有则从磁盘中读取这一页,然后缓存到内存并返回。

但是内存的价值较高,一般来说服务器的内存总是小于磁盘大小的,而且内存不能完全分配给数据库作为缓冲池。这就意味着数据库基本上无法将所有的数据都缓冲到内存中。

当缓冲池满后,如果还有新的页面要被缓冲到池中,就要设计一种页面置换的算法,将一个旧的页面替换成新的页面。

最佳置换算法(OPT(MIN)算法)

选未来最远将使用的页淘汰,是一种最优的方案,可以证明缺页数最小。可惜,需要知道将来发生的事,只能在理论中存在,实际不可应用。

先进先出算法(FIFO算法)

一种很简单的算法,其基本思想是形成一个队列,最先入队的页面最先被逐出。我们用示意图来模拟一下FIFO算法:

先进先出算法(FIFO算法)

我们的内存假设只能保存4个页面,此时的访问请求按照时间顺序是1->2->3->4->5,那么按照时间顺序,当访问到4号页面时队列正好填满,当要访问5号页面时,会将最先入队的1号页面逐出。

这种算法实现起来很简单,但是从实现上来看,性能和OPT算法差距最大。因为被替换出去的页面很有可能是最常使用的页面,因此这个算法很少见出现在数据库缓冲池管理中的。

FIFO算法会出现一个叫做Belay异常的现象,就这个现象我们解释如下。

我们首先定义一个4个页面长度的队列作为缓冲池,然后按照下面的顺序访问:1->2->3->4->5->3->9->1->4->2->7->4->7。那么我们按照刚才描述的FIFO来看看访问的过程:

访问顺序 访问页 内存队列 是否命中
1 1 1
2 2 1,2
3 3 1,2,3
4 4 1,2,3,4
5 5 2,3,4,5
6 3 2,3,4,5
7 9 3,4,5,9
8 1 4,5,9,1
9 4 4,5,9,1
10 2 5,9,1,2
11 7 9,1,2,7
12 4 1,2,7,4
13 7 1,2,7,4

从这个表格上看到,非命中次数有9次,那么我们将这个队列的容量增加到5,然后再次重复这个访问序列,看看效果:

访问顺序 访问页 内存队列 是否命中
1 1 1
2 2 1,2
3 3 1,2,3
4 4 1,2,3,4
5 5 1,2,3,4,5
6 3 1,2,3,4,5
7 9 2,3,4,5,9
8 1 3,4,5,9,1
9 4 3,4,5,9,1
10 2 4,5,9,1,2
11 7 5,9,1,2,7
12 4 9,1,2,7,4
13 7 9,1,2,7,4

这样的话,非命中的次数是10次,奇怪的是增加了缓冲池的容量,非命中缓冲的数量还增加了,这种现象就叫做Belay异常。这种算法不应该被考虑。

最近最少使用算法 LRU(Least-Recently-Used)算法

用过去的历史预测将来,选最近最长时间没有使用的页淘汰(也称最近最少使用)。性能最接近OPT。与页面使用时间有关。LRU算法的思想也很简单,实现一个链表(双向链表),每次要缓冲新的页面时,遍历链表,选择最近最少使用的页面进行逐出操作。

这种算法要求每个页面上记录一个上次使用时间t,程序决定逐出时,以这个时间t为准,t距离当前时间最大的,就是要被逐出的页面。下图中按照1->5->2->2->6->5->4的顺序访问,内存和访问示意图如下

最近最少使用算法 LRU(Least-Recently-Used)算法

其中最接近顶端的页面我们认为其t最小,最接近底部,我们认为其t最大。访问6号页面的时候,内存被填满,下一次访问5号页面的时候,会将5号页面提升到顶部,也就是t最小,之后访问4号页面,因为原先内存中没有4号页面,因此会选择逐出一个页面。此时1号页面在底部,其t最大,因此被逐出。

那么LRU算法是否解决了Belay异常呢?还是按照上一节的实验顺序,测试容量为4和5的内存,左侧到右侧,t逐渐增大:

访问顺序 访问页 内存队列 是否命中
1 1 1
2 2 1,2
3 3 1,2,3
4 4 1,2,3,4
5 5 2,3,4,5
6 3 2,4,5,3
7 9 4,5,3,9
8 1 5,3,9,1
9 4 3,9,1,4
10 2 9,1,4,2
11 7 1,4,2,7
12 4 1,2,7,4
13 7 1,2,4,7

一共有10次未命中。增加容量到5,看一下新的情况:

访问顺序 访问页 内存队列 是否命中
1 1 1
2 2 1,2
3 3 1,2,3
4 4 1,2,3,4
5 5 1,2,3,4,5
6 3 1,2,4,5,3
7 9 2,4,5,3,9
8 1 4,5,3,9,1
9 4 5,3,9,1,4
10 2 3,9,1,4,2
11 7 9,1,4,2,7
12 4 9,1,2,7,4
13 7 9,1,2,4,7

未命中的次数已经变成了9次,减少了一次,如果我设计的队列中有大量的重复,那么这个改进应该更加明显。LRU算法在系统的实现中是被改进的,每次新添加进去的页面会被放在队列的3/8处。无论如何,LRU算法都被认为是最接近OPT的算法。

LRU简单实现:采用链式结构,越早加入到链中数据,顺序越靠近尾部,后来加入的数据添加到头部。当开始需要访问数据时,先遍历链表,分两种情况。
(1)存在数据:数据在头部,则直接返回,不需要做操作。数据不在头部,将数据移动到头部(注意在尾部的情况)
(2)不存在数据:达到达到最大容量,删除尾部的一个元素,然后添加新元素到头部。未达到最大容量,直接添加到新元素到头部。

LRU简单实现
时钟置换算法 CLOCK(NRU)算法

时钟置换算法可以认为是一种最近未使用算法,即逐出的页面都是最近没有使用的那个。我们给每一个页面设置一个标记位u,u=1表示最近有使用u=0则表示该页面最近没有被使用,应该被逐出。

按照1-2-3-4的顺序访问页面,则缓冲池会以这样的一种顺序被填满:

1-2-3-4

注意中间的指针,就像是时钟的指针一样在移动,这样的访问结束后,缓冲池里现在已经被填满了,此时如果要按照1-5的顺序访问,那么在访问1的时候是可以直接命中缓存返回的,但是访问5的时候,因为缓冲池已经满了,所以要进行一次逐出操作,其操作示意图如下:

1-5

最初要经过一轮遍历,每次遍历到一个节点发现u=1的,将该标记位置为0,然后遍历下一个页面,一轮遍历完后,发现没有可以被逐出的页面,则进行下一轮遍历,这次遍历之后发现原先1号页面的标记位u=0,则将该页面逐出,置换为页面5,并将指针指向下一个页面。

假设我们接下来会访问2号页面,那么可以直接命中指针指向的页面,并将这个页面的标记为u置为1。<br />

但是考虑一个问题,数据库里逐出的页面是要写回磁盘的,这是一个很昂贵的操作,因此我们应该优先考虑逐出那些没有被修改的页面,这样可以降低IO。

因此在时钟置换算法的基础上可以做一个改进,就是增加一个标记为m,修改过标记为1,没有修改过则标记为0。那么u和m组成了一个元组,有四种可能,其被逐出的优先顺序也不一样:

7、什么是虚拟内存

虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存。

8、中断的概念

处理器接收到来自硬件或软件的信号,提示发生了某个事件,应该被注意,这种情况就称为中断。

9、什么是死锁?死锁产生的必要条件,如果避免?

死锁是指多个进程因循环等待资源而造成无法执行的现象。死锁会造成进程无法执行,同时会造成系统资源的极大浪费(资源无法释放)。

主要原因:系统资源不足、进程运行推进顺序不合适、资源分配不当

四个必要条件(都成立,才会发生死锁):

死锁避免:(银行家算法)判断此次请求是否造成死锁若会造成死锁,则拒绝该请求

10、进程与线程的区别

进程是系统进行资源调度和分配的一个独立单位
线程是进程的实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位
进程拥有独立的地址空间,而线程间共享地址空间

11、线程同步的方式

互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问
信号量:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
事件(信号):通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。

参考文献

页面置换算法之Clock算法

上一篇下一篇

猜你喜欢

热点阅读