在内存管理中,进程的逻辑地址空间被分为一个一个页面。同样的,在外存管理中,为了方便对文件数据的管理,文件的逻辑地址空间也被分为了一个一个的文件“块”。
于是文件的逻辑地址也可以表示为(逻辑块号,块内地址)的形式。
连续分配方式要求每个文件在磁盘上占用一组连续的块。
当访问一个文件时,用户给出要访问的逻辑块号,操作系统找出该文件对应的目录项(FCB)… ,物理块号 = 起始块号 + 逻辑块号。当然,还需要检查用户提供的逻辑块号是否合法(逻辑块号 ≥ 长度 就不合法)。
我们知道,读取某个磁盘块时,需要移动磁头。访问的两个磁盘块相隔越远,移动磁头所需时间就越长。所以连续分配的文件在顺序读/写时速度最快。同时,由于物理上采用连续分配,存储空间利用率低,会产生难以利用的磁盘碎片,可以用紧凑来处理碎片,但是用紧凑来处理碎片需要耗费很大的时间代价。
链接分配采用离散分配的方式,可以为文件分配离散的磁盘块。分为隐式链接和显式链接两种。
那么如何实现文件的逻辑块号到物理块号的转变?
用户给出要访问的逻辑块号 i,操作系统找到该文件对应的目录项(FCB)…;从目录项中找到其实块号(即0号块),将0号逻辑块读入内存,由此知道1号逻辑块存放的物理块号,于是读入1号逻辑块,再找到2号逻辑块的存放位置…,以此类推。
因此,读入i号逻辑块,总共需要 i + 1 次磁盘 I/O。
结论:采用链式分配(隐式链接)方式的文件,只支持顺序访问,不支持随机访问。查找效率低。另外,指向下一个盘块的指针也需要耗费少量的存储空间。
显示链接是指将用于链接各物理块的指针显示地存放在一张表中。即文件分配表(FAT,File Allocation Table)。
假设某个新建的文件“aaa”依次存放在磁盘块 2→5→0→1。那么就可以直接在 FAT 中找到最开始的起始块号,然后读取到下一块,即5,依次类推,到最后到1的时候下一块为-1,表明是终止块号。
注意:一个磁盘仅设置一张 FAT。开机时,将 FAT 读入内存,并常驻内存。FAT 的各个表项在物理上连续存储。且每一个表项长度相同,因此”物理块号“字段可以是隐含的。
如何实现文件的逻辑块号到物理块号的转变?
从目录项中找到起始块号,若 i > 0,则查询内存中的文件分配表 FAT,往后找到 i 号逻辑块对应的物理块号。逻辑块号转换成物理块号的过程不需要读磁盘操作。
结论:采用链式分配(显示链接)方式的文件,支持顺序访问,也支持随机访问(想访问 i 号逻辑块时,并不需要依次访问之前的 0 ~ i - 1 号逻辑块),由于块号转换的过程不需要访问磁盘,因此相比于隐式链接来说,访问速度快很多。显然,显示链接也不会产生外部碎片,也可以很方便地对文件进行扩展。
索引分配允许文件离散地分配在各个磁盘块中,系统会为每个文件建立一张索引表,索引表中记录了文件的各个逻辑块对应的物理块(索引表的功能类似于内存管理中的页表——建立逻辑页面到物理页之间的映射关系)。索引表存放的磁盘块称为索引块。文件数据存放的磁盘块称为数据块。
如何实现文件的逻辑块号到物理块号的转换?
用户给出要访问的逻辑块号 i,操作系统找到该文件对应的目录项(FCB)…
从目录项中可知索引表存放位置,将索引表从外存读入内存,并查找索引表即可知 i 号逻辑块在外存中的存放位置。可见,索引分配方式可以支持随机访问。文件扩展也很容易实现(只需要给文件分配一个空闲块,并增加一个索引表项即可)。但是索引表需要占用一定的存储空间。
若每个磁盘块1 KB,一个索引表项4 B,则一个磁盘块只能存放 256 个索引项。如果一个文件的大小超过了 256 块,那么一个磁盘块是装不下文件的整张索引表的,如何解决这个文件?
大概有三个解决方案:链接方案、多层索引、混合索引。
空闲表法属于连续分配方式,它与内存的动态分配方式雷同,它为每个文件分配一块连续的存储空间,即系统也为外存上所有空闲区建立一张空闲表,每个空闲区对应于一个空闲表项,其中包括表项序号、该空闲区的第一个盘块号、该区的空闲盘块号等信息,再将所有空闲区按其所有空闲区按其起始盘块号递增排列。
空闲盘块的分配与内存的动态分配类似,同样采用首次适应算法、循环首次适应算法等系统在对用户所释放的存储空间进行回收时,也采取类似于内存回收的方法,即考虑回收区是否与空闲表中插入点的前区和后区相邻接,对相邻接者应该予以合并。当文件较小时,采用连续分配方式,当文件较大时,可采用离散分配方式。
空闲链表法是将所有空闲盘区拉成一条空闲链。把链表分成两种形式,空闲盘块链和空闲盘区链。
空闲盘块链,这是将磁盘上的所有空闲空间,以盘块为单位拉成一条链,当用户因创建文件而请求分配存储空间时,系统从链首开始,依次摘下适当数目的空闲盘块分配给用户,当删除文件而释放空间时,系统将回收的盘块依次插入空闲盘块链的末尾,其优点是用于分配和回收一个盘块的过程简单,但在为文件分配盘块时,可能要重复操作多次。
空闲盘区链,这是将磁盘上的所有空闲盘区(每个盘区可包含若干个盘块)拉成一条链,在每个盘区上除了含有只是下一个空闲盘区的指针外,还应有能指明本盘区大小(盘块数)的信息。盘区分配与内存的动态分配类似,可采用首次适应算法,在回收盘区时,同样也要将回收区和相邻接的空闲盘区相合并,在采用首次适应算法时,可以采用显式链接法提高检索速度,在内存中为空闲盘区建立一张链表。
利用二进制的一位表示磁盘中的一个盘块的使用情况,当其值为0时,表示对应的盘块空闲,为1时,表示已经分配,磁盘上的所有盘块都有一个二进制位与之对应,这样,由所有盘块所对应的位构成一个集合,称为位示图,通常可用m * n个位数来构成位示图,并使m * n等于磁盘的总块数。
对于盘块的分配分为如下三步:
对于盘块的回收分为如下两步:
此方法的优点在于从位示图中很容易找到一个或一组相邻接的空闲盘块,此外,由于位示图很小,占用空间少,因而可将其保存在内存中,进而使在每次进行盘区分配时,无需首先把盘区分配表读入内存,节省磁盘启动时间。
空闲表法和空闲链表法都不适用于大型系统,因为这会使空闲表或空闲链表很长,在UNIX采用的成组链接法,结合上述两种方法。
当系统要为用户分配文件所需的盘块时,须调用盘块分配过程来完成。该过程首先检查空闲盘块号栈是否上锁,如未上锁,便从 栈顶取出一空闲盘块号,将与之对应的盘块分配给用户,然后将栈顶指针下移一格。若该盘块号已是栈底,即S.free(0),这是当前栈中最后一个可分配的 盘块号。由于在该盘块号所对应的盘块中记有下一组可用的盘块号,因此,须调用磁盘读过程,将栈底盘块号所对应盘块的内容读入栈中,作为新的盘块号栈的内 容,并把原栈底对应的盘块分配出去(其中的有用数据已读入栈中)。然后,再分配一相应的缓冲区(作为该盘块的缓冲区)。最后,把栈中的空闲盘块数减1并返回。
在系统回收空闲盘块时,须调用盘块回收过程进行回收。它是将回收盘块的盘块号记入空闲盘块号栈的顶部,并执行空闲盘块数加1操作。当栈中空闲盘块号数目已达100时,表示栈已满,便将现有栈中的100个盘块号,记入新回收的盘块中,再将其盘块号作为新栈底。
资料收集于王道考研PPT以及网络。