实验三 最佳适应算法 实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
最佳适应算法实验报告
一、实验目的
了解首次适应算法、最佳适应方法、最差适应算法
二、实验方法
修改Minix操作系统的内存分配源码,实现最佳适应算法
三、实验任务
修改Minix操作系统中的内存分配源码,将首次适应算法更改为最佳适应算法。重新编译系统映像文件,观察实验结果。
四、实验要点
内存分配、首次适应算法、最佳适应算法。
五、实验内容
5.1 minix内存分配源码
安装好minix操作系统以后,minix系统的源码位于/usr/src目录中。其中,与内存分配的相关源码则在/usr/src/servers/pm/alloc.c中。minix系统初始的内存分配算法为首次适应算法。
在minix系统中,空闲的内存空间信息采用链表的信息储存起来,而操作系统分配内存空间的过程则是在这个链表中寻找一个合适空间,返回内存空间的地址,再更改链表中的内存空间信息。这就是minix系统分配内存的实质。
5.2分析首次适应算法
首次适应算法,指的从空闲内存块链表的第一个结点开始查找,把最先找到的满足需求的空闲内存块分配出去。这种算法的优点是分配所需的时间较短,但这种算法会形成低地址部分形成很多的空间碎片,高地址区保留大量长度较长的空闲内存块。
内存分配的操作在/usr/src/servers/pm/alloc.c源文件中的alloc_mem函数中完成。在函数的初始位置,定义了两个用于遍历链表的指针变量,两个指针变量的定义如下:registerstruct hole *hp, *prev_ptr;
而hole结构体的定义如下:
PRIVATE struct hole {
struct hole *h_next;
phys_clicksh_base;
phys_clicksh_len;
} hole[NR_HOLES];
先分析这个结构体的定义,这个结构体中,有三个变量,h_next是一个指向链表下一个结点的指针变量;h_base则是指向这个链表所表示的空闲内存空间的地址,h_len 则是这个空闲内存空间的长度;phys_clicks的定义可以在/usr/src/include/minix/type.h 中找到,phys_clicks的定义为:
typedef unsigned intpyhs_clicks;
phys_clicks其实就是无符号的整数类型。
另外,在函数中,还有一个变量,old_base,数据类型为phys_clicks,用于保存找到的内存空间地址。
在寻找合适的内存空间之前,先初始化两个指针变量的值:
prev_ptr = NIL_HOLE;
hp = hole_head;
这两句代码把hp这个指针变量指向了储存空闲内存空间链表的头结点。而prev_ptr 指针在指针遍历的过程中指向hp指针变量指向结点的前驱结点;此时,hp指针变量指向的是链表的头结点,所以prev_ptr的变量值为NIL_HOLE。
在为这两个指针变量赋值以后,是通过一个while循环,直到找到满足需要的内存大小块。循环代码如下:
while (hp != NIL_HOLE &&hp->h_base … } hp指针变量就是系统用于遍历链表的指针。操作系统运行的过程中也会占用部分内存,这部分的内存不允许被分配给其他的程序,也不能通过交换机制把数据储存到硬盘之中,所以,在寻找空闲空间的过程中,不予对操作系统占用的内存空间进行查找,所以需要通过hp->h_base 在while循环中,含有一个if的分支结构;循环体中代码结构如下: if (hp->h_len>= clicks) { … } prev_ptr=hp; hp=hp->h_next; 结合上面对结构体的分析,如果hp指向的链表结点中,空闲空间的长度大于或等于请求分配的大小,则进入if代码块;否则,prev_ptr和hp指向下一个结点。 如果找到操作系统找到了符合条件的空闲内存块,进入if代码块;if代码块中的代码,简单来说可以分成两部分,第一部分是修改储存空闲内存块信息的链表;另外一部分就是把找到的地址返回。其中,第一部分的代码如下: old_base = hp->h_base; hp->h_base += clicks; hp->h_len -= clicks; if (hp->h_len == 0)del_slot(prev_ptr, hp); 第一行代码,使用一个变量,把分配出去的内存块的首地址记录下来;第二行代码,因为要把首地址为hp->h_base,大小为clicks的内存空间分配出去,所以要把这个空闲内存块的起始地址往后移动clicks,即对hp->h_base变量进行加法运算;第三行代码,更改空闲内存块的大小,即对hp->h_len变量进行减法操作。最后,进行一个简单的判断。如果长度为0,即表示这个链表结点表示的空闲内存块已经全部被分出去,要在链表中删除这个结点。 第二部分的代码只有一句: return (old_base) 把找到的满足条件的内存块的首地址返回。 上面整个的内存块寻找过程是放在一个do… while循环中。循环语句为 do {… } while (swap_out()) swap_out函数的作用是寻找一个可以被从内存中转移到磁盘中的进程,并把它转移 到磁盘之中以腾出相应的内存空间。也就是说,如果找不到合适的储存空间,系统会先尝试把部分的进程从内存移动到磁盘中;如果找不到合适的内存空间,而且也没有可以被移动到磁盘的进程时,整个函数就会返回NO_MEM,表示系统找不到合适的内存空间。 5.3改写为最佳适应算法 最佳适应算法是从所有适合的空闲内存块找出最小的空闲内存块,这种方法的优点是产生的空闲内存块碎片最小。缺点是搜索合适内存块的空闲时间比首次适应算法长,效率低。 跟首次适应算法不一样的是,最佳适应算法中,需要有一个变量,在查找过程中记录找到最小空闲内存块的大小和地址,如果刚好找到一个大小等于所需要大小的空闲内存块,则立即返回,不再寻找。 在函数的起始位置声明一些变量,代码如下: registerstruct hole *hp, *prev_ptr, *min_hp; phys_clicksold_base, min_size, found = 0; 其中,hp, prev_ptr和old_base的变量含义与首次适应算法中这些变两个的含义相同。min_hp是用于记录储存有大小最小并满足需要的空闲内存块信息的链表结点,min_size则表示到目前为止找到的空闲内存块的最小的大小值,用于查找过程中的大小比对。found则是一个标记位,表示是否已经找到了合适的空闲内存块。 修改以后,跟首次适应算法一样,查找空闲内存块的代码放在一个do…while循环中,其意义在于当不能找到合适的空闲内存块时,操作系统先进行交换,再寻找空闲的内存地址块;如果对内存空间进行交换以后仍然没有合适的空闲内存块,则会返回一个内存不足的错误信息。 在进行寻找前,需要对一些变量进行赋初值变量,赋初值的语句为: prev_ptr=NIL_HOLE; hp=hole_head; min_hp=NIL_HOLE; min_size=0xFFFFFFFF; found = 0; 上面两句代码的意义与首次适应算法中的语句意义相同,都是为了设置链表遍历操作的起点位置。把指向最小内存块对应的链表结点的指针变量设置为NIL_HOLE,同时将标记位设置为0,表示没有找到满足条件的空闲内存块。把min_size的值设置为0xFFFFFFFF(unsigned int能够表示的最大整数),以确保第一个空闲的链表结点能够始终满足比min_size小的条件。 用于寻找空闲内存块的代码跟首次适应算法一样,都是通过while循环实现,代码如下: while (hp != NIL_HOLE &&hp->h_base 这里的while条件与首次适应算法中的条件相同。while循环体中的代码可以分成两部分,第一部分是寻找合适的内存块中大小最小的内存块,另外一部分就是修改链表信息并把找到的内存块地址返回。 其中,第一部分的代码为: if (hp->h_len==clicks) { old_base=hp->h_base; del_slot(prev_ptr, hp);