内存管理(模拟题)

【问题描述】

离第一个操作系统OS发布已经没有多少时间了,但它的一些组件还没有完成,内存管理器就是其中之一。根据开发人员的计划,在第一个版本中,内存管理器将非常简单和直观。它将支持三个操作:

  • alloc n —— 分配n个字节内存,返回已分配块的正整数标识符x(x初始值为0,每次分配增长1)

  • erase x —— 删除标识符x所在的块

  • defragment —— 整理空余内存碎片,将所有块尽量靠近内存的开始位置,并保持各自的顺序

在此情况下,内存模型非常简单,它是一个m字节的序列,为了方便起见,从第一个字节到第m字节进行编号。

第一个操作alloc n有一个参数n,表示被分配的内存块大小。在处理此操作时,内存中将分配n个连续字节的空闲块。 如果这些块的数量超过一个,则优先选择最接近内存开始(即第一个字节)的块。 所有这些字节都被标记为非空闲,内存管理器返回一个32位整数数字令牌,代表该块的标识符。 如果不可能分配这样大小的空闲块,则返回NULL。

第二个操作erase x以x为参数,表示某个块的标识符。此操作释放系统内存,将此块的字节标记为空闲以供进一步使用。 如果此标识符没有指向先前分配的块(该块尚未被释放),则返回ILLEGAL_ERASE_ARGUMENT。

最后一个操作defragment没有任何参数,只会使占用的内存部分更接近内存的开始,而不会更改它们各自的顺序。

在当前的实现中,将使用从1开始的连续整数作为标识符。每个成功的alloc操作过程都应该返回接下来的编号。不成功的alloc操作不影响计数。

编写内存管理器的实现,为每个alloc命令输出返回的值,为所有失败的erase命令输出ILLEGAL_ERASE_ARGUMENT。

【输入形式】

输入数据的第一行包含两个正整数t和m(1<=t<=500, 1<=m<=10(5)),其中t表示需要内存管理器来处理的操作个数,m表示有效的内存字节大小。接下来的t行每一行代表一个操作。

【输出形式】

输出有多行,每行或者是alloc操作的结果,或者是失败的erase操作的结果ILLEGAL_ERASE_ARGUMENT。其顺序与输入的操作次序一致。

【样例输入】

6 10
alloc 5
alloc 3
erase 1
alloc 6
defragment
alloc 6

【样例输出】

1
2
NULL
3

解题步骤

  1. 初始化内存步骤:

    1. 从命令行读取t、m

    2. 初始化ArrayList v,大小为m,赋值0代表内存空闲。 (使用到ArrayList的.add(i)方法)

处理操作:

  1. 遍历t,从命令行读取操作oper

    1. 初始化mark = 0,用于标记生成的唯一内存标识符

    2. if判断是“alloc”操作

      1. 从命令行读取需要分配的内存大小size

      2. 调用alloc方法

        1. 初始化起始位置start = -1,以防未找到情况

        2. 找空余位置:循环遍历内存v,并设空余空间为free = 0

          1. if判断,当前值是否为空 v.get(i) == 0,如果是,if判断++free == size,是否已经找到size个大小的空余空间,找到的话,更改start起始值 = i - size + 1;break跳出循环因为已经找到距离起始值最近的空闲值

          2. 如果不是,重制 free = 0;

        3. 空余位置赋值标识符

          1. 如果没找到,if判断start == -1,输出“NULL”

          2. 找到

            1. 为size个内存循环赋值标识符mark+1

            2. 输出++mark

            3. 返回mark

    3. else if判断是erase操作:

      1. 从命令行读取读取需要释放的内存块标识符id

      2. 调用erase方法

        1. flag = 0

        2. 遍历内存列表,将所有值等于指定标识符的元素重新标记为0,并将flag = 1(使用到ArrayList的.get(i)方法、.set(i, 0)方法)

        3. if判断如果flag = 1,如果没有找到指定标识符的内存块,输出ILLEGAL_ERASE_ARGUMENT

    4. defragment操作:

      1. 调用erase方法执行操作

        1. 保存当前v的size

        2. v.removeIf(n -> n == 0); 移除所有值为0的元素

        3. 如果内存v.size() < size,添加到足够size的空标识符(使用到ArrayList的.add(i)方法)

输入输出处理:

  • 序首先读取操作数量和内存大小,然后根据读入的操作类型调用相应的处理函数。

  • 对于每个alloc操作,输出分配的内存块的标识符;对于失败的erase操作,输出错误信息。

关键点

  • 使用ArrayList模拟内存是这个解决方案的核心,它允许我们通过索引直接访问和修改内存的任何部分。

  • 维护一个全局的标识符计数器(mark数组),为每个成功分配的内存块分配一个唯一的标识符。

  • 通过遍历和修改ArrayList的方式来实现内存的分配、释放和整理。

Java代码

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 读取操作次数t和内存大小m
        int t = scanner.nextInt(), m = scanner.nextInt();
        // 初始化内存列表v,大小为m,初始值全部为0表示空闲
        List<Integer> v = new ArrayList<>(m);
        for (int i = 0; i < m; i++) v.add(0);

        // mark用于为每个分配的内存块生成唯一标识符
        int mark = 0;

        // 循环处理t次操作
        while(t-- > 0){
            // 读取操作类型
            String oper = scanner.next();
            if(oper.equals("alloc")){
                // 分配内存操作,读取需要分配的大小
                int size = scanner.nextInt();
                // 调用alloc方法进行内存分配,并更新mark值
                mark = alloc(v, size, mark);
            }else if(oper.equals("erase")){
                // 释放内存操作,读取需要释放的内存块标识符
                int id = scanner.nextInt();
                // 调用erases方法进行内存释放
                erases(v, id);
            }else if(oper.equals("defragment")){
                // 内存碎片整理操作
                defragment(v);
            }
        }
        scanner.close();
    }

    // alloc方法用于分配内存
    private static int alloc(List<Integer> v, int size, int mark) {
        int start = -1; // 记录找到的空闲块的起始位置
        // 遍历内存列表寻找足够大的连续空闲块
        for (int i = 0, free = 0; i < v.size(); i++) {
            if (v.get(i) == 0) {
                // 空闲块大小增加
                if (++free == size) {
                    // 找到足够大的空闲块,记录起始位置并退出循环
                    start = i - size + 1;
                    break;
                }
            } else {
                // 遇到已分配的内存,重置空闲块计数器
                free = 0;
            }
        }
        if (start == -1) {
            // 未找到足够大的空闲块,输出NULL
            System.out.println("NULL");
        } else {
            // 在找到的空闲块位置分配内存,更新内存块的标识符
            for (int i = start; i < start + size; i++) v.set(i, mark + 1);
            // 输出分配的内存块标识符
            System.out.println(++mark);
        }
        // 返回更新后的mark值
        return mark;
    }

    // erases方法用于释放内存
    private static void erases(List<Integer> v, int id) {
        int flag = 0; // 标记是否找到并释放了指定的内存块
        // 遍历内存列表,寻找并释放指定标识符id的内存块
        for (int i = 0; i < v.size(); i++) {
            if(v.get(i) == id){
                // 将内存块标记为0,表示释放
                v.set(i, 0);
                flag = 1;
            }
        }
        if(flag == 0) {
            // 如果未找到指定的内存块,输出错误信息
            System.out.println("ILLEGAL_ERASE_ARGUMENT");
        }
    }

    // defragment方法用于内存碎片整理
    private static void defragment(List<Integer> v) {
        int size = v.size();
        // 移除所有标记为0的元素(空闲内存)
        v.removeIf(n -> n == 0);
        // 补回被移除的空闲内存,保持内存大小不变
        while(v.size() < size) v.add(0);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

漫谈音频深度伪造技术

作为人工智能时代的新型媒体合成技术&#xff0c;深度伪造技术近年来在网络媒体中的涉及领域越发广泛、出现频次越发频繁。据路透社报道&#xff0c;2023年&#xff0c;社交媒体网站上发布50万个深度伪造的语音和视频。 1、深度伪造技术的五个方面 音频深度伪造技术&#xff…

Spring拦截器

一、简介&#xff1a; Spring Boot 拦截器是面向切面编程-----AOP 的具体实现&#xff0c;用于对请求做预处理。 1.1.什么是拦截器&#xff1a;在AOP&#xff08;Aspect-Oriented Programming&#xff09;中用于在某个方法或字段被访问之前&#xff0c;进行拦截然后在之前或之…

华为二层交换机与路由器连通上网实验

华为二层交换机与路由器连通上网实验 二层交换机是一种网络设备&#xff0c;用于在局域网&#xff08;LAN&#xff09;中转发数据帧。它工作在OSI模型的第二层&#xff0c;即数据链路层。二层交换机通过学习和维护MAC地址表&#xff0c;实现了数据的快速转发和广播域的隔离。 实…

读天才与算法:人脑与AI的数学思维笔记19_深度数学

1. 深度数学 1.1. 组合与选择&#xff0c;是发明新事物的两个不可或缺的条件 1.1.1. 保尔瓦雷里&#xff08;Paul Valry&#xff09; 1.2. 利用以往的数学定理证明过程训练算法&#xff0c;以发现新的定理 1.3. 谷歌设在伦敦的总部整体有一种现代牛津大学的感觉&#xff0c…

17_Scala面向对象高阶功能

文章目录 1.继承1.1 构造对象时,父类对象优于子类对象1.2父类主构造有参数,子类必须要显示地调用父类主构造器并传值 2.封装3.抽象3.1抽象定义3.2子类继承抽象类3.3抽象属性 4.伴生对象4.1创建类和伴生对象4.2调用 1.继承 –和Java一样,权限protected , public.父类定义子类用…

【Java】基本程序设计结构(二)

前言&#xff1a;上一篇我们详细介绍了Java基本程序设计结构中前半部分&#xff0c;一个简单的Java应用&#xff0c;注释&#xff0c;数据类型&#xff0c;变量与常量&#xff0c;运算符&#xff0c;字符串。包括本篇将延续上篇内容介绍后续内容&#xff0c;包括输入输出&#…

UE5 UMG

锚点 参考链接&#xff1a;虚幻5UI系统&#xff08;UMG&#xff09;基础&#xff08;已完结&#xff09;_哔哩哔哩_bilibili

政安晨:【Keras机器学习示例演绎】(三十七)—— 在计算机视觉中学习调整大小

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 本文目标&#xff1a;在计算机视觉中学习调整大小…

数据结构(十一)----图的应用

目录 一.最小生成树 1.Prim算法&#xff08;普里姆&#xff09; 2.Kruskal算法(克鲁斯卡尔): 二.最短路径&#xff08;BFS算法&#xff09; 1.单源最短路径 &#xff08;1&#xff09;BFS算法&#xff08;无权图&#xff09; &#xff08;2&#xff09;Dijkstra算法&…

QT+网络调试助手+TCP客户端

一、网络调试助手UI界面 编程主要思路&#xff1a; 首先将水平的控件 水平布局 &#xff0c;然后相对垂直的控件 垂直布局 &#xff0c;哪怕是底下的groupBox也需要和里面的内容 水平布局&#xff0c;然后最后框选全部 栅格布局。如果需要界面自适应窗口大小&#xff0c…

JavaScript js写九九乘法表(两种方法)

方法一&#xff1a; 观察规律&#xff1a; 第一个数每行都是自增1。 我们发下第二个数都是从1开始&#xff0c;依次递增1&#xff0c;永远不大于前面的数。 前面数字每自增一次&#xff0c;后面数字自增一轮。 我们可以用双重for循环&#xff0c;外层初始值设为i&#xff0…

【C++】对文章分词,并对词频用不同排序方法排序,比较各排序算法效率

文章分词 1&#xff0e;问题描述2&#xff0e;需求分析3&#xff0e;概要设计3.1 主程序流程3.2 函数调用关系 4&#xff0e;主函数实现4.1 main.h4.2 main.cpp 5. 函数实现5.1 processDic函数5.2 forwardMax函数5.3 countWordFreq函数5.4 quickResult函数5.5 其它排序算法效率…

【链表】:链表的带环问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;数据结构 &#x1f337;追光的人&#xff0c;终会万丈光芒 前言&#xff1a; 链表的带环问题在链表中是一类比较难的问题&#xff0c;它对我们的思维有一个比较高的要求&#xff0c;但是这一类…

十二、泛型

这里写自定义目录标题 一、什么是泛型二、为什么需要泛型&#xff1f;三、自定义泛型结构1、泛型类2、泛型方法 四、泛型在继承上的体现五、通配符的使用1、注意点2、有限制的通配符 一、什么是泛型 泛型就是定义类、接口时通过一个标识表示类中某个属性的类型 、方法的返回值…

C#实现简单音乐文件解析播放——Windows程序设计作业2

1. 作业内容 编写一个C#程序&#xff0c;要求实现常见音乐文件的播放功能&#xff0c;具体要求如下&#xff1a;     1). 播放MP3文件&#xff1a; 程序应能够读取MP3文件&#xff0c;并播放其中的音频。     2). 播放OGG文件&#xff1a; 应能够播放ogg文件。     …

学习3:scrapy请求对象、模拟登录、POST请求、管道的使用、crawlspider爬虫类

请求对象 请求对象参数 scrapy.Request(url[],callback,method"GET",headers,body,cookies,meta,dont_filterFalse)callback 表示当前的url响应交给那个函数去处理method 指定请求方式headers 接受一个字典&#xff0c;其中不包括cookiesbody 接收json字符串&#…

OpenCV的周期性噪声去除滤波器(70)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV如何通过梯度结构张量进行各向异性图像分割(69) 下一篇 :OpenCV如何为我们的应用程序添加跟踪栏(71) 目录 目标 理论 如何消除傅里叶域中的周期性噪声&#xff1f; 源代码 解释 结果 目…

IDEA--debug

1. 单点调试的三个级别 Step into&#xff1a;在单步执行时&#xff0c;遇到子函数就进入并且继续单步执行。Step over&#xff1a;在单步执行时&#xff0c;在函数内遇到子函数时不会进入子函数内单步执行&#xff0c;而是将子函数整个执行完再停止&#xff0c;也就是把子函数…

用树莓派2B当web服务器

树莓派2&#xff0c;卡片大小&#xff0c;arm 32位cpu&#xff0c;512G内存。我找了一下购买记录&#xff0c;2013年12月15日买的。带网线接头。属于树莓派2B。以前下载的操作系统还在。是2014年的操作系统&#xff0c;文件名是&#xff1a;2014-09-09-wheezy-raspbian_shumeip…

C语言之整形提升和算术转换

目录 前言 一、整形提升 二、算术转换 总结 前言 本文主要介绍C语言中的整形提升和算术转换的概念和意义&#xff0c;以及例题帮助理解&#xff0c;了解之后&#xff0c;我们就能知道在C语言中&#xff0c;字符型变量如何计算以及如果变量的类型、字节大小不一致的情况下&am…
最新文章