【Linux实践2】实验四:存储管理

文章目录

    • 一、存储管理的目的
      • 1.1 内存空间的分配与回收
      • 1.2 地址转换
      • 1.3 内存保护
      • 1.4 内存共享
      • 1.5 内存扩充
    • 二、可变分区存储管理
      • 2.1 分区结构体定义
      • 2.2 初始化分区链表
    • 三、内存分配算法实现
      • 3.1 首次适应算法(First Fit)
        • 3.1.1 算法实现
      • 3.2 循环首次适应算法(Next Fit)
        • 3.2.1 算法实现
      • 3.3 最佳适应算法(Best Fit)
        • 3.3.1 算法实现
    • 四、内存回收与分区链表维护
      • 4.1 回收内存
      • 4.2 打印分区链表状态
    • 五、实验结果与分析
      • 5.1 分配作业
      • 5.2 回收内存
      • 5.3 最终状态
      • 5.4 完整代码
      • 5.3 输出结果


一、存储管理的目的

1.1 内存空间的分配与回收

操作系统需要确保每个程序都能获得所需的内存空间,并在不需要时释放内存,以避免资源浪费。

1.2 地址转换

操作系统为每个程序提供相对地址或虚拟地址,并负责将这些地址转换为物理地址。

1.3 内存保护

防止一个程序访问另一个程序的内存空间,确保系统的稳定性和安全性。

1.4 内存共享

允许多个程序共享同一块内存区域,提高内存使用效率。

1.5 内存扩充

通过虚拟内存技术,使得程序可以使用比物理内存更大的地址空间。

二、可变分区存储管理

2.1 分区结构体定义

我们定义了一个分区结构体Partition,用于描述内存分区的状态,包括分区的ID、大小、起始地址、状态(空闲或已分配)以及指向下一个分区的指针。

typedef struct Partition {int id;int size;int start;int status;  // 0表示空闲,1表示已分配struct Partition *next;
} Partition;

2.2 初始化分区链表

通过initPartitionList函数,我们初始化了一个分区链表,模拟了内存的初始状态。

Partition* initPartitionList() {Partition *head = (Partition *)malloc(sizeof(Partition));head->id = 0;head->size = 1024;  // 假设初始内存大小为1024head->start = 0;head->status = 0;head->next = NULL;return head;
}

三、内存分配算法实现

3.1 首次适应算法(First Fit)

首次适应算法从内存分区链表的开始进行搜索,找到第一个足够大的空闲分区进行分配。

3.1.1 算法实现

firstFit函数中,我们遍历分区链表,寻找第一个状态为空闲且大小足够大的分区进行分配,并可能进行分区分割。

Partition* firstFit(Partition *head, int jobSize) {Partition *curr = head;while (curr != NULL) {if (curr->status == 0 && curr->size >= jobSize) {// 如果找到合适的空闲分区,进行分配curr->status = 1;// 如果分区大小大于作业需求,进行分割if (curr->size > jobSize) {Partition *newPartition = (Partition *)malloc(sizeof(Partition));newPartition->id = curr->id + 1;newPartition->size = curr->size - jobSize;newPartition->start = curr->start + jobSize;newPartition->status = 0;newPartition->next = curr->next;curr->size = jobSize;curr->next = newPartition;}return curr;}curr = curr->next;}return NULL;  // 未找到合适分区
}

3.2 循环首次适应算法(Next Fit)

循环首次适应算法从上一次分配结束的位置开始搜索,而不是从头开始。

3.2.1 算法实现

circularFirstFit函数中,我们使用一个last指针来记录上次分配的结束位置,并从该位置开始搜索合适的分区。

Partition* circularFirstFit(Partition *head, int jobSize) {Partition *curr = head;Partition *last = NULL;do {if (curr->status == 0 && curr->size >= jobSize) {// 如果找到合适的空闲分区,进行分配curr->status = 1;// 如果分区大小大于作业需求,进行分割if (curr->size > jobSize) {Partition *newPartition = (Partition *)malloc(sizeof(Partition));newPartition->id = curr->id + 1;newPartition->size = curr->size - jobSize;newPartition->start = curr->start + jobSize;newPartition->status = 0;newPartition->next = curr->next;curr->size = jobSize;curr->next = newPartition;}return curr;}last = curr;curr = curr->next;} while (curr != head);return NULL;  // 未找到合适分区
}

3.3 最佳适应算法(Best Fit)

最佳适应算法搜索整个分区链表,找到能够满足请求且剩余空间最小的空闲分区进行分配。

3.3.1 算法实现

bestFit函数中,我们遍历整个分区链表,记录并返回最小的足够大的空闲分区。

Partition* bestFit(Partition *head, int jobSize) {Partition *best = NULL;Partition *curr = head;while (curr != NULL) {if (curr->status == 0 && curr->size >= jobSize) {if (best == NULL || curr->size < best->size) {best = curr;}}curr = curr->next;}if (best != NULL) {best->status = 1;// 如果分区大小大于作业需求,进行分割if (best->size > jobSize) {Partition *newPartition = (Partition *)malloc(sizeof(Partition));newPartition->id = best->id + 1;newPartition->size = best->size - jobSize;newPartition->start = best->start + jobSize;newPartition->status = 0;newPartition->next = best->next;best->size = jobSize;best->next = newPartition;}}return best;  // 返回找到的最佳分区或NULL(未找到合适分区)
}

四、内存回收与分区链表维护

4.1 回收内存

releaseMemory函数中,我们释放了指定分区的内存,并尝试与相邻的空闲分区合并,以减少内存碎片。

void releaseMemory(Partition *head, int partitionId) {Partition *curr = head;Partition *prev = NULL;while (curr != NULL && curr->id != partitionId) {prev = curr;curr = curr->next;}if (curr != NULL) {curr->status = 0;// 合并相邻的空闲分区if (prev != NULL && prev->status == 0) {prev->size += curr->size;prev->next = curr->next;free(curr);curr = prev;}if (curr->next != NULL && curr->next->status == 0) {curr->size += curr->next->size;Partition *temp = curr->next;curr->next = curr->next->next;free(temp);}}
}

4.2 打印分区链表状态

printPartitionList函数用于打印当前分区链表的状态,包括每个分区的ID、大小、起始地址和状态。

void printPartitionList(Partition *head) {Partition *curr = head;printf("分区ID\t分区大小\t起始地址\t状态\n");while (curr != NULL) {printf("%d\t\t%d\t\t%d\t\t%s\n", curr->id, curr->size, curr->start,curr->status == 0 ? "空闲" : "已分配");curr = curr->next;}
}

五、实验结果与分析

5.1 分配作业

通过调用不同的内存分配函数,我们为作业分配了内存,并记录了分配结果。

int main() {Partition *head = initPartitionList();// 使用首次适应算法分配作业Partition *assignedPartition1 = firstFit(head, 200);if (assignedPartition1 != NULL) {printf("首次适应算法:作业分配到分区ID:%d\n", assignedPartition1->id);} else {printf("首次适应算法:未找到合适分区分配作业\n");}// 使用循环首次适应算法分配作业Partition *assignedPartition2 = circularFirstFit(head, 300);if (assignedPartition2 != NULL) {printf("循环首次适应算法:作业分配到分区ID:%d\n", assignedPartition2->id);} else {printf("循环首次适应算法:未找到合适分区分配作业\n");}// 使用最佳适应算法分配作业Partition *assignedPartition3 = bestFit(head, 150);if (assignedPartition3 != NULL) {printf("最佳适应算法:作业分配到分区ID:%d\n", assignedPartition3->id);} else {printf("最佳适应算法:未找到合适分区分配作业\n");}// 回收内存releaseMemory(head, assignedPartition1->id);releaseMemory(head, assignedPartition2->id);releaseMemory(head, assignedPartition3->id);// 打印分区链表最终状态printPartitionList(head);return 0;

5.2 回收内存

作业完成后,我们调用内存回收函数释放内存,并观察了分区链表的变化。

5.3 最终状态

实验结束时,我们打印了分区链表的最终状态,以验证内存分配和回收的正确性。

5.4 完整代码

#include <stdio.h>
#include <stdlib.h>// 定义分区结构体
typedef struct Partition {int id;int size;int start;int status;  // 0表示空闲,1表示已分配struct Partition *next;
} Partition;// 初始化分区链表
Partition* initPartitionList() {Partition *head = (Partition *)malloc(sizeof(Partition));head->id = 0;head->size = 1024;  // 假设初始内存大小为1024head->start = 0;head->status = 0;head->next = NULL;return head;
}// 首次适应算法分配内存
Partition* firstFit(Partition *head, int jobSize) {Partition *curr = head;while (curr!= NULL) {if (curr->status == 0 && curr->size >= jobSize) {// 如果找到合适的空闲分区,进行分配curr->status = 1;// 如果分区大小大于作业需求,进行分割if (curr->size > jobSize) {Partition *newPartition = (Partition *)malloc(sizeof(Partition));newPartition->id = curr->id + 1;newPartition->size = curr->size - jobSize;newPartition->start = curr->start + jobSize;newPartition->status = 0;newPartition->next = curr->next;curr->size = jobSize;curr->next = newPartition;}return curr;}curr = curr->next;}return NULL;  // 未找到合适分区
}// 循环首次适应算法分配内存
Partition* circularFirstFit(Partition *head, int jobSize) {Partition *curr = head;Partition *last = NULL;do {if (curr->status == 0 && curr->size >= jobSize) {// 如果找到合适的空闲分区,进行分配curr->status = 1;// 如果分区大小大于作业需求,进行分割if (curr->size > jobSize) {Partition *newPartition = (Partition *)malloc(sizeof(Partition));newPartition->id = curr->id + 1;newPartition->size = curr->size - jobSize;newPartition->start = curr->start + jobSize;newPartition->status = 0;newPartition->next = curr->next;curr->size = jobSize;curr->next = newPartition;}return curr;}last = curr;curr = curr->next;} while (curr!= head);return NULL;  // 未找到合适分区
}// 最佳适应算法分配内存
Partition* bestFit(Partition *head, int jobSize) {Partition *best = NULL;Partition *curr = head;while (curr!= NULL) {if (curr->status == 0 && curr->size >= jobSize) {if (best == NULL || curr->size < best->size) {best = curr;}}curr = curr->next;}if (best!= NULL) {best->status = 1;// 如果分区大小大于作业需求,进行分割if (best->size > jobSize) {Partition *newPartition = (Partition *)malloc(sizeof(Partition));newPartition->id = best->id + 1;newPartition->size = best->size - jobSize;newPartition->start = best->start + jobSize;newPartition->status = 0;newPartition->next = best->next;best->size = jobSize;best->next = newPartition;}}return best;  // 返回找到的最佳分区或NULL(未找到合适分区)
}// 回收内存
void releaseMemory(Partition *head, int partitionId) {Partition *curr = head;Partition *prev = NULL;while (curr!= NULL && curr->id!= partitionId) {prev = curr;curr = curr->next;}if (curr!= NULL) {curr->status = 0;// 合并相邻的空闲分区if (prev!= NULL && prev->status == 0) {prev->size += curr->size;prev->next = curr->next;free(curr);curr = prev;}if (curr->next!= NULL && curr->next->status == 0) {curr->size += curr->next->size;Partition *temp = curr->next;curr->next = curr->next->next;free(temp);}}
}// 打印分区链表状态
void printPartitionList(Partition *head) {Partition *curr = head;printf("分区ID\t分区大小\t起始地址\t状态\n");while (curr!= NULL) {printf("%d\t\t%d\t\t%d\t\t%s\n", curr->id, curr->size, curr->start,curr->status == 0? "空闲" : "已分配");curr = curr->next;}
}int main() {Partition *head = initPartitionList();// 使用首次适应算法分配作业Partition *assignedPartition1 = firstFit(head, 200);if (assignedPartition1!= NULL) {printf("首次适应算法:作业分配到分区ID:%d\n", assignedPartition1->id);} else {printf("首次适应算法:未找到合适分区分配作业\n");}// 使用循环首次适应算法分配作业Partition *assignedPartition2 = circularFirstFit(head, 300);if (assignedPartition2!= NULL) {printf("循环首次适应算法:作业分配到分区ID:%d\n", assignedPartition2->id);} else {printf("循环首次适应算法:未找到合适分区分配作业\n");}// 使用最佳适应算法分配作业Partition *assignedPartition3 = bestFit(head, 150);if (assignedPartition3!= NULL) {printf("最佳适应算法:作业分配到分区ID:%d\n", assignedPartition3->id);} else {printf("最佳适应算法:未找到合适分区分配作业\n");}// 回收内存releaseMemory(head, assignedPartition1->id);releaseMemory(head, assignedPartition2->id);releaseMemory(head, assignedPartition3->id);// 打印分区链表最终状态printPartitionList(head);return 0;
}

5.3 输出结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/475058.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux 中mysql查看慢日志

1、到mysql容器&#xff0c;先登录到数据库&#xff0c;查看是否开启 mysql -h 127.0.0.1 -uroot -p SHOW VARIABLES LIKE slow_query_log; 2、如果没有开启&#xff0c;需要先开启 set global slow_query_log ON; 3、查看慢日志文件 SHOW VARIABLES LIKE slow_query_log…

微服务day09

DSL查询 快速入门 GET /items/_search {"query": {"match_all": {}} } 叶子查询 GET /items/_search {"query": {"match_all": {}} }GET /items/_search {"query": {"multi_match": {"query": "脱…

vue中el-select 模糊查询下拉两种方式

第一种&#xff1a;先获取所有下拉数据再模糊查询&#xff0c;效果如下 1&#xff0c;页面代码&#xff1a;speciesList是种类列表List, speciesId 是speciesList里面对应的id&#xff0c;filterable是过滤查询标签 <el-form-item label"种类" prop"species…

django启动项目报错解决办法

在启动此项目报错&#xff1a; 类似于&#xff1a; django.core.exceptions.ImproperlyConfigured: Requested setting EMOJI_IMG_TAG, but settings are not c启动方式选择django方式启动&#xff0c;以普通python方式启动会报错 2. 这句话提供了对遇到的错误的一个重要线索…

【Redis】Redis实现的消息队列

一、用list实现【这是数据类型所以支持持久化】 消息基于redis存储不会因为受jvm内存上限的限制&#xff0c;支持消息的有序性&#xff0c;基于redis的持久化机制&#xff0c;只支持单一消费者订阅&#xff0c;无法避免消息丢失。 二、用PubSub【这不是数据类型&#xff0c;是…

【AI+教育】一些记录@2024.11.16

《万字长文&#xff0c;探讨关于ChatGPT的五个最核心问题》 万字长文&#xff0c;探讨关于ChatGPT的五个最核心问题关于 ChatGPT 铺天盖地的信息让人无所适从。本文则试图提炼出五个关键问题&#xff1a;如何理解这次范式突破&#xff0c;未来能达到的技术天花板&#xff0c;行…

【计算机网络】TCP协议

一、TCP协议格式 1.报头的含义 (1) 16位源端口号/16位目的端口号 自己的端口号 和 对方的端口号 (2) 4位首部长度 表示报头长度&#xff08;TCP报头总长度 4位首部长度 * 4字节&#xff09;最少有20字节 TCP报头总长度 -> 0000 ~ 1111 -> [0, 15] * 4 -> [0, 60…

http自动发送请求工具(自动化测试http请求)

点击下载《http自动发送请求工具(自动化测试http请求)》 前言 在现代软件开发过程中&#xff0c;HTTP 请求的自动化测试是确保应用程序稳定性和可靠性的关键环节。为了满足这一需求&#xff0c;我开发了一款功能强大且易于使用的自动化 HTTP 请求发送工具。该工具基于 C# 开发…

C++ —— 剑斩旧我 破茧成蝶—C++11

江河入海&#xff0c;知识涌动&#xff0c;这是我参与江海计划的第2篇。 目录 1. C11的发展历史 2. 列表初始化 2.1 C98传统的{} 2.2 C11中的{} 2.3 C11中的std::initializer_list 3. 右值引用和移动语义 3.1 左值和右值 3.2 左值引用和右值引用 3.3 引用延长生命周期…

Leetcode 有效的数独

这段代码解决的是 验证一个数独是否有效 的问题&#xff0c;其算法思想是基于 规则校验和状态记录。具体思想如下&#xff1a; 算法思想 核心目标&#xff1a; 检查每个数字在 同一行、同一列 和 同一个 3x3 子格 中是否重复。 状态记录&#xff1a; 使用 3 个布尔二维数组分别…

STM32设计学生宿舍监测控制系统-分享

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 本项目旨在利用STM32单片机为核心&#xff0c;结合传感器技术、无线通信技…

RabbitMQ消息可靠性保证机制4--消费端限流

7.7 消费端限流 在类似如秒杀活动中&#xff0c;一开始会有大量并发写请求到达服务端&#xff0c;城机对消息进行削峰处理&#xff0c;如何做&#xff1f; 当消息投递的速度远快于消费的速度时&#xff0c;随着时间积累就会出现“消息积压”。消息中间件本身是具备一定的缓冲…

爬虫开发工具与环境搭建——使用Postman和浏览器开发者工具

第三节&#xff1a;使用Postman和浏览器开发者工具 在网络爬虫开发过程中&#xff0c;我们经常需要对HTTP请求进行测试、分析和调试。Postman和浏览器开发者工具&#xff08;特别是Network面板和Console面板&#xff09;是两种最常用的工具&#xff0c;能够帮助开发者有效地捕…

单片机实验记录3

定时计数实验 【实验目的】 1)学习使用单片机定时/计数器 2)在程序中添加定时/计数功能&#xff0c;将相关程序部署在仿真环境中&#xff0c;观察运行的情况. 【实验内容】 必做&#xff1a;应用定时器中断和数码管&#xff0c;实现10秒倒计时功能 【实验代码】 必做&am…

(计算机毕设)基于SpringBoot+Vue的房屋租赁系统的设计与实现

博主可接毕设设计&#xff01;&#xff01;&#xff01; 各种毕业设计源码只要是你有的题目我这里都有源码 摘 要 社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。网络计算机的生活方式逐渐受到广大人民群众的喜爱&#xff0c;也逐渐进入了每个用户的使用。互…

创新租赁APP开发提升用户体验与业务效率

内容概要 在这个互联网飞速发展的时代&#xff0c;租赁APP的开发成为了提升市场竞争力的重要一环。用户对租赁服务的需求与日俱增&#xff0c;而传统的方式已显得不够高效。这时候&#xff0c;创新的租赁APP就像是一道光&#xff0c;照亮了用户体验和业务效率的双重需求。通过…

【Java SE】数据库连接池

数据库连接池是一个管理数据库连接的容器。它的主要作用是分配和管理数据库连接&#xff0c;允许应用程序重复使用现有的连接&#xff0c;而不是每次都重新建立新的连接。此外&#xff0c;连接池会释放那些空闲时间超过最大限制的连接&#xff0c;从而避免因未及时释放连接而造…

SpringBoot 集成 Sharding-JDBC(一):数据分片

在深入探讨 Sharding-JDBC 之前&#xff0c;建议读者先了解数据库分库分表的基本概念和应用场景。如果您还没有阅读过相关的内容&#xff0c;可以先阅读我们之前的文章&#xff1a; 关系型数据库海量数据存储策略-CSDN博客 这篇文章将帮助您更好地理解分库分表的基本原理和实现…

多线程--常见锁策略--Java

目录 一、悲观锁VS乐观锁 1.悲观锁 2.乐观锁 二、重量级锁VS轻量级锁 1.重量级锁 2.轻量级锁 三、自旋锁 1.自旋锁概念 四、公平锁VS非公平锁 1.公平锁 2.非公平锁 3.注意 五、可重入锁和不可重入锁 六、读写锁 1.线程对于数据的访问方式 注意&#xff1a;以下讲…

基于SSM的农家乐管理系统+论文示例参考

1.项目介绍 功能模块&#xff1a;管理员&#xff08;农家乐管理、美食信息管理、住宿信息管理、活动信息、用户管理、活动报名、论坛等&#xff09;&#xff0c;普通用户&#xff08;注册登录、活动报名、客房预订、用户评价、收藏管理、模拟支付等&#xff09;技术选型&#…