4.23实验二:存储管理动态分区分配及回收算法
实验二:存储管理动态分区分配及回收算法
一、实验目的
分区管理是应用较广泛的一种存储管理技术。本实验要求用一种结构化高级语言构造分区描述器,编制动态分区分配算法和回收算法模拟程序,并讨论不同分配算法的特点。
二、实验要求
1、编写: First Fit Algorithm
2、编写:Best Fit Algorithm
3、编写:空闲区回收算法
提示和说明:
(一)主程序
1、定义分区描述器 node,包括 3个元素:
(1)adr--分区首地址
(2)size--分区大小
(3)next--指向下一个分区的指针
2、定义 3个指向 node 结构的指针变量:
(1)head1--空闲区队列首指针
(2)back1--指向释放区 node 结构的指针
(3)assign--指向申请的内存分区 node 结构的指针
3、定义1个整形变量:
fee--用户申请存储区的大小(由用户键入)
(二)过程
1、定义 check 过程,用于检查指定的释放块(由用户键入)的合法性
2、定义assignmentl 过程,实现 First Fit Algorithm
3、定义assignment2 过程,实现 Best Fit Algorithm
4、定义 acceptment1 过程,实现 First Fit Algorithm 的回收算法
5、定义 acceptment2 过程,实现 Best FitAlgorithm 的回收算法
6、定义print过程,打印空闲区队列
(三)执行
程序首先申请一整块空闲区,其首址为0,大小为32767:然后,提示用户使用哪种分配算法,再提示是分配还是回收;分配时要求输入申请区的大小,回收时要求输入释放区的首址和大小。
(四)输出
要求每执行一次,输出一次空闲区队列情况,内容包括:编号,首址,终址,大小
注:输出空闲区队列的排序,应符合所用分配算法的要求。
三、实验过程
1.准备
A. 查阅相关资料:
习动态分区分配算法原理(首次适应算法、最佳适应算法)
了解内存回收时的四种情况(上邻、下邻、上下邻、不邻)
研究链表数据结构在内存管理中的应用
B. 初步编写程序:
C. 准备测试数据:
设计多种分配和回收场景
包括正常情况和边界情况测试用例
2.上机调试
测试首次适应算法
测试最佳适应算法
边界条件测试
3. 主要流程和源代码
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// 分区描述器结构
typedef struct node {
int adr; // 分区首地址
int size; // 分区大小
struct node *next; // 指向下一个分区的指针
} Node;
// 函数声明
void assignment1(Node *head, int fee); // 首次适应分配算法
void assignment2(Node *head, int fee); // 最佳适应分配算法
void acceptment1(Node *head, int adr, int size); // 首次适应回收算法
void acceptment2(Node *head, int adr, int size); // 最佳适应回收算法
void print(Node *head); // 打印空闲区队列
int check(Node *head, int adr, int size); // 检查释放块合法性
int main() {
// 初始化空闲区队列
Node *head1 = (Node*)malloc(sizeof(Node)); // 头节点
Node *init = (Node*)malloc(sizeof(Node)); // 初始空闲区
init->adr = 0;
init->size = 32767;
init->next = NULL;
head1->next = init;
int algorithm, operation, fee, adr, size;
printf("========== 动态分区管理模拟程序 ==========\n");
while(1) {
printf("\n选择分配算法: 1-首次适应 2-最佳适应 3-退出\n");
scanf("%d", &algorithm);
if(algorithm == 3) break;
if(algorithm != 1 && algorithm != 2) {
printf("无效选择!\n");
continue;
}
printf("选择操作: 1-分配 2-回收\n");
scanf("%d", &operation);
if(operation == 1) {
printf("输入申请内存大小: ");
scanf("%d", &fee);
if(fee <= 0) {
printf("申请大小必须为正数!\n");
continue;
}
if(algorithm == 1)
assignment1(head1, fee); // 首次适应
else
assignment2(head1, fee); // 最佳适应
}
else if(operation == 2) {
printf("输入释放区首址和大小: ");
scanf("%d %d", &adr, &size);
if(size <= 0) {
printf("释放大小必须为正数!\n");
continue;
}
if(!check(head1, adr, size)) {
printf("释放区不合法!\n");
continue;
}
if(algorithm == 1)
acceptment1(head1, adr, size);
else
acceptment2(head1, adr, size);
}
else {
printf("无效操作!\n");
continue;
}
print(head1); // 打印空闲区队列
}
// 释放内存
Node *p = head1->next;
while(p != NULL) {
Node *temp = p;
p = p->next;
free(temp);
}
free(head1);
return 0;
}
// 首次适应分配算法
void assignment1(Node *head, int fee) {
Node *p, *q;
q = head;
p = head->next;
while(p != NULL) {
if(p->size >= fee) { // 找到第一个足够大的空闲区
if(p->size == fee) { // 刚好满足
q->next = p->next;
printf("分配成功! 首址: %d 大小: %d\n", p->adr, fee);
free(p);
} else { // 分割空闲区
Node *alloc = (Node*)malloc(sizeof(Node));
alloc->adr = p->adr;
alloc->size = fee;
p->adr += fee;
p->size -= fee;
printf("分配成功! 首址: %d 大小: %d\n", alloc->adr, fee);
free(alloc); // 实际分配不需要保存,这里只是模拟
}
return;
}
q = p;
p = p->next;
}
printf("无足够大的空闲区!\n");
}
// 最佳适应分配算法
void assignment2(Node *head, int fee) {
Node *p, *q, *best, *best_prev;
int min_size = INT_MAX;
q = head;
p = head->next;
best = NULL;
best_prev = NULL;
while(p != NULL) {
if(p->size >= fee && p->size < min_size) {
min_size = p->size;
best = p;
best_prev = q;
}
q = p;
p = p->next;
}
if(best != NULL) {
if(best->size == fee) { // 刚好满足
best_prev->next = best->next;
printf("分配成功! 首址: %d 大小: %d\n", best->adr, fee);
free(best);
} else { // 分割空闲区
Node *alloc = (Node*)malloc(sizeof(Node));
alloc->adr = best->adr;
alloc->size = fee;
best->adr += fee;
best->size -= fee;
printf("分配成功! 首址: %d 大小: %d\n", alloc->adr, fee);
free(alloc); // 实际分配不需要保存,这里只是模拟
}
} else {
printf("无足够大的空闲区!\n");
}
}
// 首次适应回收算法
void acceptment1(Node *head, int adr, int size) {
Node *p, *q, *new_node;
int end = adr + size;
q = head;
p = head->next;
while(p != NULL && p->adr < end) {
q = p;
p = p->next;
}
// 检查是否与前面的空闲区相邻
if(q != head && (q->adr + q->size) == adr) {
q->size += size;
// 检查是否与后面的空闲区相邻
if(p != NULL && (adr + size) == p->adr) {
q->size += p->size;
q->next = p->next;
free(p);
}
}
// 检查是否与后面的空闲区相邻
else if(p != NULL && end == p->adr) {
p->adr = adr;
p->size += size;
}
// 不与任何空闲区相邻,创建新节点
else {
new_node = (Node*)malloc(sizeof(Node));
new_node->adr = adr;
new_node->size = size;
new_node->next = p;
q->next = new_node;
}
printf("回收成功! 首址: %d 大小: %d\n", adr, size);
}
// 最佳适应回收算法(与首次适应回收算法相同,因为回收逻辑不依赖分配策略)
void acceptment2(Node *head, int adr, int size) {
acceptment1(head, adr, size);
}
// 打印空闲区队列
void print(Node *head) {
Node *p = head->next;
int i = 1;
printf("\n空闲区队列:\n");
printf("编号\t首址\t终址\t大小\n");
while(p != NULL) {
printf("%d\t%d\t%d\t%d\n", i, p->adr, p->adr + p->size - 1, p->size);
p = p->next;
i++;
}
}
// 检查释放块合法性(简化版,实际应检查是否与已分配区重叠)
int check(Node *head, int adr, int size) {
// 检查释放区是否在合法范围内
if(adr < 0 || adr + size > 32767) {
return 0;
}
// 检查释放区是否与空闲区重叠(简化检查)
Node *p = head->next;
while(p != NULL) {
if((adr >= p->adr && adr < p->adr + p->size) ||
(adr + size > p->adr && adr + size <= p->adr + p->size)) {
return 0;
}
p = p->next;
}
return 1;
}
4.遇到的主要问题和解决方法
A. :回收时未检查释放区是否与已分配区重叠(代码中仅检查与空闲区重叠)。
解决方法:需要维护已分配区列表或在空闲区检查时更严格(当前简化实现可能不完善)。
四、实验结果


五、实验总结
通过本次实验,我学到了动态分区管理的基本原理和实现方法,首次适应算法和最佳适应算法的特点和差异,内存回收时的合并策略,使用链表数据结构管理内存空间的方法,提高了编程能力和调试技巧。

浙公网安备 33010602011771号