实验二:存储管理动态分区分配及回收算法


 

一、实验目的

分区管理是内存管理中广泛应用的一种技术,本实验要求使用结构化的高级语言(C/C++)模拟实现动态分区分配算法和回收算法。通过编写 First Fit 算法、Best Fit 算法以及空闲区回收算法,帮助理解不同分配算法的特点,并加深对内存管理的掌握。

二、实验要求

First Fit 分配算法:

实现 First Fit 分配算法,即从空闲区队列中寻找第一个足够大的空闲分区进行分配。

 

Best Fit 分配算法:

实现 Best Fit 分配算法,即从空闲区队列中寻找最适合的空闲分区进行分配,即剩余空间最小的空闲区。

 

空闲区回收算法:

实现空闲区回收算法,支持分配后回收内存区域,并将回收的内存区域正确地合并回空闲区队列。

三、实验过程

1.准备

A. 查阅相关资料主要内容包括:

 

内存管理原理:了解操作系统中内存的分配方式,特别是动态分区分配方法。

分配算法:深入理解 First Fit 和 Best Fit 分配算法的工作原理,优缺点,以及如何在内存管理中应用这些算法。

空闲区合并:了解如何处理内存回收时的空闲区合并问题,避免内存碎片。

C语言链表操作:学习如何在 C 语言中使用链表数据结构,管理空闲区。

 

B. 初步编写程序:

定义数据结构:定义 Node 结构体,用于表示每个内存分区,包括分区的起始地址、大小、指向下一个分区的指针。

实现空闲区链表的初始化:通过链表管理空闲内存区,初始时创建一块大内存区域,设置首地址为 0,大小为 32767。

实现分配算法:编写 First Fit 和 Best Fit 分配算法的具体实现,确保能够根据用户输入的分区大小进行分配。

实现回收算法:设计回收算法,能够在内存回收后合并相邻的空闲块。

打印空闲区链表的状态:每执行一次分配或回收操作后,打印当前空闲区链表的状态。

 

C. 准备测试数据:

初始空闲区的测试:测试在程序启动时,初始化一块空闲内存区域是否正确。

分配算法的测试:设计不同的申请内存大小,测试 First Fit 和 Best Fit 算法的表现,验证内存是否按照算法要求分配。

回收操作的测试:模拟回收内存并合并相邻空闲块,验证回收和合并功能是否正常工作。

 

 

边界测试:设计极端测试案例,如内存申请大小为 0、内存回收超出范围、空闲区链表为空时进行分配等,确保程序能够处理各种边界情况。

 

2.上机调试

  1. 主要流程和源代码

初始化一个空闲区,首地址为 0,大小为 32767。

提示用户选择分配算法:First Fit 或 Best Fit。

提示用户选择是进行分配还是回收操作。

如果是分配操作,要求输入申请区的大小;如果是回收操作,要求输入释放区的首地址和大小。

每执行一次分配或回收操作,输出空闲区队列的状态。

#include <stdio.h>

#include <stdlib.h>

 

// 分区描述器

typedef struct node {

    int adr;            // 分区起始地址

    int size;           // 分区大小

    struct node *next;  // 下一个分区

} Node;

 

// 全局指针

Node *head1 = NULL;     // 空闲区队列头

Node *assign = NULL;    // 指向申请到的分区

int free_size;          // 用户申请大小

 

// 函数声明

void init_free_area(int total_size);

void print_free_list();

int check_release(int adr, int size);

void first_fit_allocate();

void best_fit_allocate();

void first_fit_release();

void best_fit_release();

void sort_free_list_by_addr();

 

// 主程序

int main() {

    int choice, op;

    init_free_area(32767);  // 初始一块 0~32766 大小的空闲区

 

    while (1) {

        printf("\n请选择分配算法:1-First Fit  2-Best Fit  0-退出 :");

        scanf("%d", &choice);

        if (choice == 0) break;

 

        printf("1-分配  2-回收  :");

        scanf("%d", &op);

        if (op == 1) {

            printf("输入申请分区大小:");

            scanf("%d", &free_size);

            if (choice == 1) first_fit_allocate();

            else             best_fit_allocate();

        } else if (op == 2) {

            int adr, size;

            printf("输入释放分区首址和大小:");

            scanf("%d %d", &adr, &size);

            if (!check_release(adr, size)) {

                printf("释放区不合法,跳过。\n");

            } else {

                free_size = size;

                // 先将这块释放区插入到空闲链表

                Node *p = (Node *)malloc(sizeof(Node));

                p->adr  = adr;

                p->size = size;

                p->next = head1;

                head1  = p;

                // 再不同算法合并相邻空闲块

                if (choice == 1) first_fit_release();

                else             best_fit_release();

            }

        } else {

            printf("无效操作!\n");

        }

        print_free_list();

    }

    return 0;

}

 

// 初始化空闲区链表

void init_free_area(int total_size) {

    head1 = (Node *)malloc(sizeof(Node));

    head1->adr  = 0;

    head1->size = total_size;

    head1->next = NULL;

    printf("初始化空闲区链表,总大小 %d\n", total_size);

    print_free_list();

}

 

// 打印空闲区链表

void print_free_list() {

    printf("\n空闲区队列情况:\n");

    printf("编号\t首址\t终址\t大小\n");

    Node *p = head1;

    int idx = 1;

    while (p) {

        printf("%d\t%d\t%d\t%d\n", idx, p->adr, p->adr + p->size - 1, p->size);

        p = p->next; idx++;

    }

}

 

// 检查释放区合法性(简单示例:首址>=0 且 size>0)

int check_release(int adr, int size) {

    if (adr < 0 || size <= 0) return 0;

    return 1;

}

 

// First Fit 分配

void first_fit_allocate() {

    Node *p = head1, *prev = NULL;

    while (p) {

        if (p->size >= free_size) {

            // 找到首个满足的块

            assign = p;

            break;

        }

        prev = p;

        p = p->next;

    }

    if (!p) {

        printf("没有合适的空闲区,无法分配!\n");

        return;

    }

    printf("分配:起始地址 %d,大小 %d\n", assign->adr, free_size);

    assign->adr += free_size;

    assign->size -= free_size;

    if (assign->size == 0) {

        // 整块用完,从链表中移除

        if (prev) prev->next = assign->next;

        else      head1 = assign->next;

        free(assign);

    }

}

 

// Best Fit 分配

void best_fit_allocate() {

    Node *p = head1, *prev = NULL;

    Node *best = NULL, *best_prev = NULL;

    while (p) {

        if (p->size >= free_size) {

            if (!best || p->size < best->size) {

                best = p;

                best_prev = prev;

            }

        }

        prev = p;

        p = p->next;

    }

    if (!best) {

        printf("没有合适的空闲区,无法分配!\n");

        return;

    }

    printf("分配:起始地址 %d,大小 %d\n", best->adr, free_size);

    best->adr  += free_size;

    best->size -= free_size;

    if (best->size == 0) {

        if (best_prev) best_prev->next = best->next;

        else           head1 = best->next;

        free(best);

    }

}

 

// First Fit 回收(合并相邻空闲区)

void first_fit_release() {

    sort_free_list_by_addr();

    Node *p = head1;

    while (p && p->next) {

        if (p->adr + p->size == p->next->adr) {

            // 相邻,合并

            p->size += p->next->size;

            Node *tmp = p->next;

            p->next = tmp->next;

            free(tmp);

        } else {

            p = p->next;

        }

    }

}

 

// Best Fit 回收(逻辑同 First Fit,保留按大小查找特性,可以不排序)

void best_fit_release() {

    // 回收时同样需要按地址合并,否则会产生碎片

    first_fit_release();

}

 

// 按首址升序排序空闲链表(冒泡法)

void sort_free_list_by_addr() {

    if (!head1 || !head1->next) return;

    int swapped;

    do {

        swapped = 0;

        Node **pp = &head1;

        while ((*pp)->next) {

            if ((*pp)->adr > (*pp)->next->adr) {

                // 交换节点指针

                Node *tmp = *pp;

                *pp = tmp->next;

                tmp->next = (*pp)->next;

                (*pp)->next = tmp;

                swapped = 1;

            }

            pp = &((*pp)->next);

        }

    } while (swapped);

}

 

4.遇到的主要问题和解决方法

A. 空闲区回收算法中的内存合并问题

在回收内存时,特别是在first_fit_release和best_fit_release中,我们尝试将相邻的空闲块合并。这个过程有时可能导致不正确的合并,尤其是在多个释放区之间的地址顺序不完全连续时。

解决方法:

排序:为了确保释放的区块能够与相邻的空闲区合并,我们首先需要对空闲区链表进行排序,按照首地址升序排列。这样可以确保释放的区块能够与其相邻的块合并。

逐个检查:通过遍历整个空闲区链表,逐个检查是否存在相邻的块,如果发现两个块是相邻的(一个块的终址等于另一个块的首址),就进行合并操作。

B. 分配算法中的空闲区选择问题

在first_fit_allocate和best_fit_allocate中,如何选择合适的空闲区是一个关键问题。对于First Fit,我们从头开始查找第一个足够大的块进行分配;而Best Fit则寻找剩余空间最小的块。 

解决方法:

First Fit:尽量避免遍历不必要的空闲区链表,如果找到合适的块就立刻分配。

Best Fit:为避免碎片过多,可以在分配前对空闲区进行合并,减少碎片的产生。

C. 空闲区打印时的输出格式问题

在输出空闲区链表时,可能会遇到格式显示不清楚的问题,特别是在分区大小很大或链表很长时,输出的结果可能会显得杂乱。

 

解决方法:

确保输出时对齐,并使用适当的格式化控制符来美化输出,使其更易读。

 

四、实验结果

    

 

五、实验总结

 

posted @ 2025-05-06 22:52  艾鑫4646  阅读(77)  评论(0)    收藏  举报