本文共 4695 字,大约阅读时间需要 15 分钟。
一.成组链接法介绍
在UNIX系统中,将空闲块分成若干组,每100个空闲块为一组,每组的第一空闲块登记了下一组空闲块的物理盘块号和空闲块总数。
在UNIX系统中,将空闲块分成若干组,每100个空闲块为一组,每组的第一空闲块登记了下一组空闲块的物理盘块号和空闲块总数。如果一个组的第二个空闲块号等于0,则有特殊的含义,意味着该组是最后一组,即无下一个空闲块。
分配空闲块的时候,从前往后分配,先从第一组开始分配,第一组空闲的100块分完了,才进入第二组。
释放空闲块的时候正好相反,从后往前分配,先将释放的空闲块放到第一组,第一组满了,在第一组前再开辟一组,之前的第一组变成第二组。
二.详细讲解分配过程
首先我们来看一个图,这里我们假设系统具有7个盘块,每组3块,最左边的0解释代表第一块。
2.1.模拟
首先看空闲盘块号栈,也就是第一组的第一块,数字为3,表示有三个空闲盘块,之后它有一个指针指向了1号连接盘块,是是因为它的第一块空闲盘块块号为1,再接着看1号连接盘块指向了4号连接盘块,是因为它的第一块盘号为4,以此类推。
2.2.空闲块的分配
到达栈顶,块号为3,我们可以先把3分配出去,接下来我们可以继续把2号给分配出去,如下图
分配完之后,我们发现这时空闲盘块号栈只剩一块了,如果再想分配就会变成空栈了。没有空闲盘块,进程就会阻塞。所以,需要把1号盘块号链的内容拷贝到空闲盘块号栈,然后再分配1号空闲盘块,如下图:
2.3.对应的java代码实现逻辑如下:
//分配空闲块public static void allocate() { //空闲块数,分配的盘块号 int freeNum, allocativeNum; //当前组盘块大于1块 if (groups[0][0] > 1) { freeNum = groups[0][0]; allocativeNum = groups[0][freeNum]; groups[0][0]--; freeList.remove((Integer) allocativeNum); System.out.println("分配的块号为:" + allocativeNum); } //只剩一个空闲块 else if (groups[0][0] == 1) { //不是链尾,还有其它空闲块组 if (groups[0][1] != 0) { allocativeNum = groups[0][1]; for (int j = 0; j < groups[allocativeNum].length; j++) //当前组已经分配完,下一组拷贝到当前组 groups[0][j] = groups[allocativeNum][j]; //groups[0][0]--; freeList.remove((Integer) allocativeNum); System.out.println("分配的块号为:" + allocativeNum); } else { System.out.println("已经没有空闲块了"); return; } } //当前组已经分配完 else { System.out.println("当前组已经分配完了"); } display();}
1.首先判断空闲盘块号栈的盘块是否大于1块,如果是,就得到它的块数,然后把最后一块给分配出去,然后块数减1。
2.如果只剩一个空闲块了呢,首先还得判断它的第一个数是否为0,因为0代表最后一组,表示已经没有空闲盘块号了;否则,把下一组的内容拷贝到空闲盘块号栈,如果allocativeNum是1的话,对应二维数组的第一行,也就是上面的1号盘块号链。
3.若果空闲盘块号都不满足以上条件,表示为0,已经分配完了。
2.4.空闲盘块的回收
1.首先我们回收刚才分配的3号盘块,但是我们发现空闲盘块已经满了,如果想回收3号,我们需要将空闲盘块的内容移动到3号盘块号链上,然后空闲盘块号链的指针指向3号空闲盘块号链,如图:
2.其他盘块的回收同理:
2.5.下面是java代码的模拟实现:
//回收空闲块public static void recycling() { int freeNum; System.out.println("请输入你想回收的空闲盘块的盘块号:"); int recyclingNum = scanner.nextInt(); for (int i = 0; i < freeList.size(); i++) { if (freeList.get(i) == recyclingNum) { System.out.println("该空闲块已经存在"); return; } } //当前组不满3块 if (groups[0][0] < 3) { freeNum = groups[0][0]; groups[0][freeNum++] = recyclingNum; freeList.add(recyclingNum); groups[0][0]++; } else { for (int j = 0; j <= 3; j++) groups[recyclingNum][j] = groups[0][j]; groups[0][0] = 1; groups[0][1] = recyclingNum; freeList.add(recyclingNum); } display();}
1.首先我们是数据要回收的盘块号,然后判断是否存在。
2.如果当前组不满3块,我们就得到盘块的数目,然后把盘块添加到栈顶,盘块数加1.
3.如果当前组等于3块,我们需要把空闲盘块号栈的内容复制到盘块号链号为当前回收的盘块号的盘块号链上,如果我们回收的是3号,我们就需要把空闲盘块号栈复制到3号盘块号链上,然后空闲盘块的盘块号数目赋值为1,第一个盘块为我们刚才回收的盘块。
2.6.下面的代码是显示出当前的空闲盘块
public static void display() { //空闲盘块数 int freeNum, temp, groupNum = 1; //空闲盘块号链没有结尾,后面还有很多组 if (groups[0][1] != 0) { freeNum = groups[0][0]; System.out.println("第一组盘块:"); //输出第一组空闲盘块 for (int j = 1; j <= freeNum; j++) { System.out.print(groups[0][j] + " "); } System.out.println(); //下一组盘块 temp = groups[0][1]; //盘块组数 groupNum++; //当空闲盘块号链没有结束 while (groups[temp][1] != 0) { System.out.println("第" + groupNum + "组盘块:"); freeNum = groups[temp][0]; for (int j = 1; j <= freeNum; j++) { System.out.print(groups[temp][j] + " "); } System.out.println(); groupNum++; //s.free判断是否为末尾 temp = groups[temp][1]; } //退出后表示S.free为0,为盘块号链的结束 System.out.println("第" + groupNum + "组盘块,也是最后一组:"); freeNum = groups[temp][0]; //1号为0,所以这次从2开始 for (int j = 2; j <= freeNum; j++) { System.out.print(groups[temp][j] + " "); } System.out.println(); } //表示空闲盘块链只有一组,1为0 else { freeNum = groups[0][0]; //1表示只有0 if (freeNum == 1) { System.out.println("空闲盘块已经全部被分配:"); } else { System.out.println("第一组盘块为:"); for (int j = 2; j <= freeNum; j++) { System.out.print(groups[0][j] + " "); } System.out.println(); } }}
1.首先判断空闲盘块号栈的第一个数是否为0,判断是否为最后一条链,如果是,进入第二步,否则,进入第三步
2.判断空闲盘块数是否为0,也就是第一个数如果为1,表示只有代表结束标识的0,表示没有盘块,若非,从第一个位置开始,输出所有的空闲盘块。
3.得到空闲盘块号栈的盘块数,输出空闲盘块号栈的盘块号。
3.1.然后把空闲盘块号栈的第一个数赋值给一个临时变量,接着输出其他组的内容。
3.2.我们用一个while循环来判断,如果每一条链中的第一个数不是0,代表不是最后一条链,就需要继续输出其他组的空闲块号。
3.3.步骤基本如下:得到临时变量temp的块数,输出所有块号,然后把输出完的哪一组的第一个数赋值给临时变量判断是否为最后一组,是的话退出。
3.4.最后输出最后一组,第一个位置为0,从第二个位置开始输出。
2.7.程序运行
三.这是完整代码的连接,需要的朋友请下载