【Linux系统编程复习】一些常见的问题6

51、进程终止的方式

       进程在创建之后,它就开始运行并做完成任务。然而,没有什么事儿是永不停歇的,包括进程也一样。进程早晚会发生终止,但是通常是由于以下情况触发的:

●正常退出(自愿的)

●错误退出(自愿的)

●严重错误(非自愿的)

●被其他进程杀死(非自愿的)

(1)正常退出

多数进程是由于完成了工作而终止。当编译器完成了所给定程序的编译之后,编译器会执行一个系统调用告诉操作系统它完成了工作。这个调用在UNIX中是exit,在Windows 中是 ExitProcess。面向屏幕中的软件也支持自愿终止操作。字处理软件、Internet浏览器和类似的程序中总有一个供用户点击的图标或菜单项,用来通知进程删除它锁打开的任何临时文件,然后终止。

⑵错误退出

进程发生终止的第二个原因是发现严重错误,例如,如果用户执行如下命令

cc foo.c

为了能够编译foo.c但是该文件不存在,于是编译器就会发出声明并退出。在给出了错误参数时,面向屏幕的交互式进程通常并不会直接退出,因为这从用户的角度来说并不合理,用户需要知道发生了什么并想要进行重试,所以这时候应用程序通常会弹出—个对话框告知用户发生了系统错误,是需要重试还是退出。

⑶严重错误

进程终止的第三个原因是由进程引起的错误,通常是由于程序中的错误所导致的。例如,执行了一条非法指令,引用不存在的内存,或者除数是О等。在有些系统比如UNIX中,进程可以通知操作系统,它希望自行处理某种类型的错误,在这类错误中,进程会收到信号(中断),而不是在这类错误出现时直接终止进程。

(4)被其他进程杀死

第四个终止进程的原因是,某个进程执行系统调用告诉操作系统杀死某个进程。在UNIX中,这个系统调用是 kill。在Win32中对应的函数是TerminateProcess (注意不是系统调用)。

52、影响调度程序的指标是什么

会有下面几个因素决定调度程序的好坏:

●CPU使用率:

CPU正在执行任务(即不处于空闲状态)的时间百分比。

●等待时间

这是进程轮流执行的时间,也就是进程切换的时间

●吞吐量

单位时间内完成进程的数量

●响应时间

这是从提交流程到获得有用输出所经过的时间。

●周转时间

从提交流程到完成流程所经过的时间。

53、虚拟内存的实现方式

        虚拟内存中,允许将一个作业分多次调入内存。采用连续分配方式时,会使相当一部分内存空间都处于暂时或永久的空闲状态,造成内存资源的严重浪费,而且也无法从逻辑上扩大内存容量。因此,虚拟内存的实需要建立在离散分配的内存管理方式的基础上。虚拟内存的实现有以下三种方式:

●请求分页存储管理。

●请求分段存储管理。

●请求段页式存储管理。

不管哪种方式,都需要有一定的硬件支持。一般需要的支持有以下几个方面:

●一定容量的内存和外存。

●页表机制(或段表机制),作为主要的数据结构。

●中断机构,当用户程序要访问的部分尚未调入内存,则产生中断。

●地址变换机构,逻辑地址到物理地址的变换。

54、内存为什么要分段

         内存是随机访问设备,对于内存来说,不需要从头开始查找,只需要直接给出地址即可。内存的分段是从8086 CPU开始的,8086的CPU还是16位的寄存器宽,16位的寄存器可以存储的数字范围是2的16次方,即64 KB,8086的 CPU还没有虚拟地址,只有物理地址,也就是说,如果两个相同的程序编译出来的地址相同,那么这两个程序是无法同时运行的。为了解决这个问题,操作系统设计人员提出了让CPU使用段基址+段内偏移的方式来访问任意内存。这样的好处是让程序可以重定位,这也是内存为什么要分段的第一个原因。

那么什么是重定位呢?

简单来说就是将程序中的指令地址改为另一个地址,地址处存储的内容还是原来的。

CPU采用段基址+段内偏移地址的形式访问内存,就需要提供专门的寄存器,这些专门的寄存器就是Cs、DS、ES等。

也就是说,程序中需要用到哪块内存,就需要先加载合适的段到段基址寄存器中,再给出相对于该段基址的段偏移地址即可。CPU中的地址加法器会将这两个地址进行合并,从地址总线送入内存。

8086的 CPU有20根地址总线,最大的寻址能力是1MB,而段基址所在的寄存器宽度只有16位,最大为你64 KB的寻址能力,64 KB显然不能满足1MB的最大寻址范围,所以就要把内存分段,每个段的最大寻址能力是64KB,但是仍旧不能达到最大1 MB的寻址能力,所以这时候就需要偏移地址的辅助,偏移地址也存入寄存器,同样为64 KB的寻址能力,这么一看还是不能满足1MB的寻址,所以CPU的设计者对地址单元动了手脚,将段基址左移4位,然后再和16位的段内偏移地址相加,就达到了1MB的寻址能力。所以内存分段的第二个目的就是能够访问到所有内存。

55、物理地址、逻辑地址、有效地址、线性地址、虚拟地址的区别

物理地址就是内存中真正的地址,它就相当于是你家的门牌号,你家就肯定有这个门牌号,具有唯—性。不管哪种地址,最终都会映射为物理地址。

在实模式下,段基址+段内偏移经过地址加法器的处理,经过地址总线传输,最终也会转换为物理地址。

但是在保护模式下,段基址+段内偏移被称为线性地址,不过此时的段基址不能称为真正的地址,而是会被称作为一个选择子的东西,选择子就是个索引,相当于数组的下标,通过这个索引能够在GDT中找到相应的段描述符,段描述符记录了段的起始、段的大小等信息,这样便得到了基地址。如果此时没有开启内存分页功能,那么这个线性地址可以直接当做物理地址来使用,直接访问内存。如果开启了分页功能,那么这个线性地址又多了一个名字,这个名字就是虚拟地址。

不论在实模式还是保护模式下,段内偏移地址都叫做有效地址。有效地址也是逻辑地址。

线性地址可以看作是虚拟地址,虚拟地址不是真正的物理地址,但是虚拟地址会最终被映射为物理地址。下面是虚拟地址->物理地址的映射。

56、空闲内存管理的方式

操作系统在动态分配内存时(malloc,new),需要对空间内存进行管理。一般采用了两种方式:位图和空闲链表。

(1)使用位图进行管理

              使用位图方法时,内存可能被划分为小到几个字或大到几千字节的分配单元。每个分配单元对应于位图中的一位,0表示空闲,1表示占用(或者相反)。一块内存区域和其对应的位图如下

图a表示一段有5个进程和3个空闲区的内存,刻度为内存分配单元,阴影区表示空闲(在位图中用0表示);图b表示对应的位图;图c表示用链表表示同样的信息

分配单元的大小是一个重要的设计因素,分配单位越小,位图越大。然而,即使只有4字节的分配单元,32位的内存也仅仅只需要位图中的1位。32n位的内存需要n位的位图,所以1个位图只占用了1/32的内存。如果选择更大的内存单元,位图应该要更小。如果进程的大小不是分配单元的整数倍,那么在最后一个分配单元中会有大量的内存被浪费。

位图提供了一种简单的方法在固定大小的内存中跟踪内存的使用情况,因为位图的大小取决于内存和分配单元的大小。这种方法有一个问题,当决定为把具有k个分配单元的进程放入内存时,内容管理器(memory manager)必须搜索位图,在位图中找出能够运行k个连续О位的串。在位图中找出制定长度的连续0串是一个很耗时的操作,这是位图的缺点。(可以简单理解为在杂乱无章的数组中,找出具有一大长串空闲的数组单元)

(2)使用空闲链表

       另一种记录内存使用情况的方法是,维护一个记录已分配内存段和空闲内存段的链表,段会包含进程或者是两个进程的空闲区域。可用上面的图c来表示内存的使用情况。链表中的每一项都可以代表一个空闲区(H)或者是进程(P)的起始标志,长度和下一个链表项的位置。

        在这个例子中,段链表〈segment list)是按照地址排序的。这种方式的优点是,当进程终止或被交换时,更新列表很简单。一个终止进程通常有两个邻居((除了内存的顶部和底部外)。相邻的可能是进程也可能是空闲区,它们有四种组合方式。

当按照地址顺序在链表中存放进程和空闲区时,有几种算法可以为创建的进程(或者从磁盘中换入的进程)分配内存。

●首次适配算法:在链表中进行搜索,直到找到最初的一个足够大的空闲区,将其分配。除非进程大小和空间区大小恰好相同,否则会将空闲区分为两部分,一部分为进程使用,一部分成为新的空闲区。该方法是速度很快的算法,因为索引链表结点的个数较少。

●下次适配算法:工作方式与首次适配算法相同,但每次找到新的空闲区位置后都记录当前位置,下次寻找空闲区从上次结束的地方开始搜索,而不是与首次适配放一样从头开始;

●最佳适配算法:搜索整个链表,找出能够容纳进程分配的最小的空闲区。这样存在的问题是,尽管可以保证为进程找到一个最为合适的空闲区进行分配,但大多数情况下,这样的空闲区被分为两部分,一部分用于进程分配,一部分会生成很小的空闲区,而这样的空闲区很难再被进行利用。

●最差适配算法:与最佳适配算法相反,每次分配搜索最大的空闲区进行分配,从而可以使得空闲区拆分得到的新的空闲区可以更好的被进行利用。

57、页面置换算法都有哪些

在地址映射过程中,如果在页面中发现所要访问的页面不在内存中,那么就会产生一条缺页中断。当发生缺页中断时,如果操作系统内存中没有空闲页面,那么操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。

下面我汇总的这些页面置换算法比较齐全,只给出简单介绍,算法具体的实现和原理可以自行了解。

●最优算法在当前页面中置换最后要访问的页面。不幸的是,没有办法来判定哪个页面是最后一个要访问的,因此实际上该算法不能使用。然而,它可以作为衡量其他算法的标准。

●NRU算法根据R位和M位的状态将页面氛围四类。从编号最小的类别中随机选择一个页面。NRU算法易于实现,但是性能不是很好。存在更好的算法。

●FIFo会跟踪页面加载进入内存中的顺序,并把页面放入一个链表中。有可能删除存在时间最长但是还在使用的页面,因此这个算法也不是一个很好的选择。

●第二次机会算法是对FIFo的一个修改,它会在删除页面之前检查这个页面是否仍在使用。如果页面正在使用,就会进行保留。这个改进大大提高了性能。

●时钟算法是第二次机会算法的另外一种实现形式,时钟算法和第二次算法的性能差不多,但是会花费更少的时间来执行算法。

●LRU算法是一个非常优秀的算法,但是没有特殊的硬件(TLB)很难实现。如果没有硬件,就不能使用LRU算法。

●NFU算法是一种近似于LRU的算法,它的性能不是非常好。

●老化算法是一种更接近LRU算法的实现,并且可以更好的实现,因此是一个很好的选择

●最后两种算法都使用了工作集算法。工作集算法提供了合理的性能开销,但是它的实现比较复杂。wSclock是另外一种变体,它不仅能够提供良好的性能,而且可以高效地实现。

        最好的算法是老化算法和wSClock 算法。他们分别是基于LRU和工作集算法。他们都具有良好的性能并且能够被有效的实现。还存在其他一些好的算法,但实际上这两个可能是最重要的。

58、提高文件系统性能的方式

访问磁盘的效率要比内存慢很多,是时候又祭出这张图了

所以磁盘优化是很有必要的,下面我们会讨论几种优化方式

(1)高速缓存

最常用的减少磁盘访问次数的技术是使用块高速缓存(bock cache)或者缓冲区高速缓存(buffer cache)。高速缓存指的是一系列的块,它们在逻辑上属于磁盘,但实际上基于性能的考虑被保存在内存中。

管理高速缓存有不同的算法,常用的算法是:检查全部的读请求,查看在高速缓存中是否有所需要的块。如果存在,可执行读操作而无须访问磁盘。如果检查块不再高速缓存中,那么首先把它读入高速缓存,再复制到所需的地方。之后,对同一个块的请求都通过高速缓存来完成。

高速缓存的操作如下图所示

由于在高速缓存中有许多块,所以需要某种方法快速确定所需的块是否存在。常用方法是将设备和磁盘地址进行散列操作。然后在散列表中查找结果。具有相同散列值的块在一个链表中连接在一起(这个数据结构是不是很像HashMap?),这样就可以沿着冲突链查找其他块。

如果高速缓存已满,此时需要调入新的块,则要把原来的某一块调出高速缓存,如果要调出的块在上次调入后已经被修改过,则需要把它写回磁盘。这种情况与分页非常相似。

(2)块提前读

第二个明显提高文件系统的性能是在需要用到块之前试图提前将其写入高速缓存从而提高命中率。许多文件都是顺序读取。如果请求文件系统在某个文件中生成块k,文件系统执行相关操作并且在完成之后,会检查高速缓存,以便确定块k+1是否已经在高速缓存。如果不在,文件系统会为k+1安排一个预读取,因为文件希望在用到该块的时候能够直接从高速缓存中读取。

当然,块提前读取策略只适用于实际顺序读取的文件。对随机访问的文件,提前读丝毫不起作用。甚至还会造成阻碍。

(3)减少磁盘臂运动

高速缓存和块提前读并不是提高文件系统性能的唯一方法。另一种重要的技术是把有可能顺序访问的块放在一起,当然最好是在同一个柱面上,从而减少磁盘臂的移动次数。当写一个输出文件时,文件系统就必须按照要求一次一次地分配磁盘块。如果用位

图来记录空闲块,并且整个位图在内存中,那么选择与前一块最近的空闲块是很容易的。如果用空闲表,并且链表的一部分存在磁盘上,要分配紧邻的空闲块就会困难很多。

不过,即使采用空闲表,也可以使用块簇技术。即不用块而用连续块簇来跟踪磁盘存储区。如果一个扇区有512个字节,有可能系统采用1KB的块(2个扇区),但却按每2块(4个扇区)一个单位来分配磁盘存储区。这和2KB的磁盘块并不相同,因为在高速缓存中它仍然使用1 KB的块,磁盘与内存数据之间传送也是以1KB进行,但在一个空闲的系统上顺序读取这些文件,寻道的次数可以减少一半,从而使文件系统的性能大大改善。若考虑旋转定位则可以得到这类方法的变体。在分配块时,系统尽量把一个文件中的连续块存放在同一个柱面上。

在使用inode 或任何类似inode的系统中,另一个性能瓶颈是,读取一个很短的文件也需要两次磁盘访问:一次是访问inode,一次是访问块。通常情况下,inode的放置如下图所示

其中,全部 inode放在靠近磁盘开始位置,所以inode和它所指向的块之间的平均距离是柱面组的一半,这将会需要较长时间的寻道时间。

一个简单的改进方法是,在磁盘中部而不是开始处存放inode,此时,在inode和第一个块之间的寻道时间减为原来的一半。另一种做法是:将磁盘分成多个柱面组,每个柱面组有自己的 inode,数据块和空闲表,如上图 b所示。

当然,只有在磁盘中装有磁盘臂的情况下,讨论寻道时间和旋转时间才是有意义的。现在越来越多的电脑使用固态硬盘(ssD),对于这些硬盘,由于采用了和闪存同样的制造技术,使得随机访问和顺序访问在传输速度上已经较为相近,传统硬盘的许多问题就消失了。但是也引发了新的问题。

(4))磁盘碎片整理

在初始安装操作系统后,文件就会被不断的创建和清除,于是磁盘会产生很多的碎片,在创建一个文件时,它使用的块会散布在整个磁盘

上,降低性能。删除文件后,回收磁盘块,可能会造成空穴。

磁盘性能可以通过如下方式恢复:移动文件使它们相互挨着,并把所有的至少是大部分的空闲空间放在一个或多个大的连续区域内。Windows有一个程序defrag就是做这个事儿的。Windows用户会经常使用它,SSD除外。

磁盘碎片整理程序会在让文件系统上很好地运行。Linux文件系统(特别是ext2和ext3)由于其选择磁盘块的方式,在磁盘碎片整理上一般不会像 Windows一样困难,因此很少需要手动的磁盘碎片整理。而且,固态硬盘并不受磁盘碎片的影响,事实上,在固态硬盘上做磁盘碎片整理反倒是多此一举,不仅没有提高性能,反而磨损了固态硬盘。所以碎片整理只会缩短固态硬盘的寿命。

59、磁盘臂调度算法

一般情况下,影响磁盘快读写的时间由下面几个因素决定

●寻道时间–寻道时间指的就是将磁盘臂移动到需要读取磁盘块上的时间

●旋转延迟–等待合适的扇区旋转到磁头下所需的时间

●实际数据的读取或者写入时间

这三种时间参数也是磁盘寻道的过程。一般情况下,寻道时间对总时间的影响最大,所以,有效的降低寻道时间能够提高磁盘的读取速度。

如果磁盘驱动程序每次接收一个请求并按照接收顺序完成请求,这种处理方式也就是先来先服务(First-Come,First-served,ECFS),这种方式很难优化寻道时间。因为每次都会按照顺序处理,不管顺序如何,有可能这次读完后需要等待一个磁盘旋转一周才能继续读取,而其他柱面能够马上进行读取,这种情况下每次请求也会排队。

通常情况下,磁盘在进行寻道时,其他进程会产生其他的磁盘请求。磁盘驱动程序会维护一张表,表中会记录着柱面号当作索引,每个柱面未完成的请求会形成链表,链表头存放在表的相应表项中。

一种对先来先服务的算法改良的方案是使用最短路径优先(SSF)算法,下面描述了这个算法。

假如我们在对磁道6号进行寻址时,同时发生了对11,2 ,4,14,8,15,3的请求,如果采用先来先服务的原则,如下图所示

我们可以计算一下磁盘臂所跨越的磁盘数量为5+9+2+10+6+7+12= 51,相当于是跨越了51次盘面,如果使用最短路径优先,我们来计算一下跨越的盘面

跨越的磁盘数量为4+1+1+4+3+3+1=17,相比51足足省了两倍的时间。

但是,最短路径优先的算法也不是完美无缺的,这种算法照样存在问题,那就是优先级问题

这里有一个原型可以参考就是我们日常生活中的电梯,电梯使用一种电梯算法(elevator algorithm)来进行调度,从而满足协调效率和公平性这两个相互冲突的目标。电梯一般会保持向一个方向移动,直到在那个方向上没有请求为止,然后改变方向。

电梯算法需要维护一个二进制位,也就是当前的方向位:UP(向上)或者是DoN(向下)。当一个请求处理完成后,磁盘或电梯的驱动程序会检查该位,如果此位是UP位,磁盘臂或者电梯仓移到下一个更高跌未完成的请求。如果高位没有未完成的请求,则取相反方向。当方向位是 Do时,同时存在一个低位的请求,磁盘臂会转向该点。如果不存在的话,那么它只是停止并等待。

我们举个例子来描述一下电梯算法,比如各个柱面得到服务的顺序是4,7,10,14,9,6,3,1,那么它的流程图如下

所以电梯算法需要跨越的盘面数量是3+3+4+5+3+3+1=22

电梯算法通常情况下不如 SSF算法。

—些磁盘控制器为软件提供了一种检查磁头下方当前扇区号的方法,使用这样的控制器,能够进行另一种优化。如果对一个相同的柱面有两个或者多个请求正等待处理,驱动程序可以发出请求读写下一次要通过磁头的扇区。

这里需要注意一点,当一个柱面有多条磁道时,相继的请求可能针对不同的磁道,这种选择没有代价,因为选择磁头不需要移动磁盘臂也没有旋转延迟。

对于磁盘来说,最影响性能的就是寻道时间和旋转延迟,所以一次只读取一个或两个扇区的效率是非常低的。

出于这个原因,许多磁盘控制器总是读出多个扇区并进行高速缓存,即使只请求一个扇区时也是这样。一般情况下读取一个扇区的同时会读取该扇区所在的磁道或者是所有剩余的扇区被读出,读出扇区的数量取决于控制器的高速缓存中有多少可用的空间。

磁盘控制器的高速缓存和操作系统的高速缓存有一些不同,磁盘控制器的高速缓存用于缓存没有实际被请求的块,而操作系统维护的高速缓存由显示地读出的块组成,并且操作系统会认为这些块在近期仍然会频繁使用。

当同一个控制器上有多个驱动器时,操作系统应该为每个驱动器都单独的维护一个未完成的请求表。一旦有某个驱动器闲置时,就应该发出一个寻道请求来将磁盘臂移到下一个被请求的柱面。如果下一个寻道请求到来时恰好没有磁盘臂处于正确的位置,那么驱动程序会在刚刚完成传输的驱动器上发出一个新的寻道命令并等待,等待下一次中断到来时检查哪个驱动器处于闲置状态。

60、RAID的不同级别

RAID称为磁盘冗余阵列,简称磁盘阵列。利用虚拟化技术把多个硬盘结合在一起,成为一个或多个磁盘阵列组,目的是提升性能或数据冗余。

RAID有不同的级别

● RAID  0- 无容错的条带化磁盘阵列

● RAID  1- 镜像和双工

● RAID  2- 内存式纠错码

● RAID  3- 比特交错奇偶校验

● RAID  4- 块交错奇偶校验

● RAID  5- 块交错分布式奇偶校验

● RAID  6- P+Q冗余

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值