【C 数据结构-动态内存管理】2. 边界标识法管理动态内存

文章目录

  • 【 1. 边界标识法的结构设计 】
  • 【 2. 分配算法 】
  • 【 3. 回收算法 】
    • 3.1 空闲块两侧是占用块
    • 3.2 空闲块左侧是空闲块
    • 3.3 空闲块右侧是空闲块
    • 3.3 空闲块两侧是空闲块

  • 边界标识法 可以解决系统中内存碎片过多而无法使用的问题。

【 1. 边界标识法的结构设计 】

  • 使用边界标识法的可利用空间表本身是 双向循环链表,每个内存块结点都有指向前驱和后继结点的指针域。在使用边界标识法管理内存时,可利用空间表中的结点的构成如下图所示:每个结点中包含 3 个区域,head 域、foot 域 和 space 域:
    • space 域 表示为该内存块的大小,它的大小通过 head 域中的 size 值表示。
    • head 域 中包含有 4 部分:
      • llink 和 rlink 分别表示指向当前内存块结点的直接前驱和直接后继;
      • tag 值用于标记当前内存块的状态,是占用块(用 1 表示)还是空闲块(用 0 表示);
      • size 用于记录该内存块的存储大小。
    • foot 域 中包含有 2 部分:
      • uplink 是指针域,用于指向内存块本身,通过 uplink 就可以获取该内存块所在内存的首地址;
      • tag 同 head 域中的 tag 相同,都是记录内存块状态的。
    • PS:head 域和 foot 域在本节中都假设只占用当前存储块的 1 个存储单位的空间,对于该结点整个存储空间来说,可以忽略不计。也就是说,在可利用空间表中,知道下一个结点的首地址,该值减 1 就可以找到当前结点的 foot 域。

在这里插入图片描述

  • 边界标识法管理的内存块结点的代码表示为:
typedef struct WORD{union{struct WORD *llink;//指向直接前驱struct WORD *uplink;//指向结点本身};int tag;//标记域,0表示为空闲块;1表示为占用块int size;//记录内存块的存储大小struct WORD *rlink;//指向直接后继OtherType other;//内存块可能包含的其它的部分
}WORD,head,foot,*Space;
  • 通过以上介绍的结点结构构建的可利用空间表中,由于是双向循环链表结构,任何一个结点都可以作为该链表的头结点(用 pav 表示头结点),当头结点为 NULL 时,即可利用空间表为空,无法继续分配空间。

【 2. 分配算法 】

  • 问题描述
    当用户申请空间时,系统可以采用 首部拟合法、最佳拟合法和最差拟合法 这 3 种分配方法中的任何一种。但在不断分配的过程中,会产生一些容量极小以至无法利用的空闲块,这些不断生成的小内存块就会减慢遍历分配的速度。
  • 针对上述问题的解决措施是:
    1. 选定一个常量 e,每次向用户分配空间后,判断内存块剩余部分的容量,如果剩余部分的容量比 e 小,则将整个内存块全部分配给用户。
    2. 采用首部拟合法进行分配时,如果每次都从 pav 指向的结点开始遍历,在若干次后,会出现存储量小的结点密集地分布在 pav 结点附近的情况,严重影响遍历的时间。解决办法就是:在每次分配空间后,让 pav 指针指向该分配空间结点的后继结点,然后从新的 pav 指向的结点开始下一次的分配。
  • 分配算法的 C实现(采用首部拟合法):
Space AllocBoundTag(Space *pav,int n){Space p,f;int e=10;//设定常量 e 的值//如果在遍历过程,当前空闲块的存储容量比用户申请空间 n 值小,在该空闲块有右孩子的情况下直接跳过for (p=(*pav); p&&p->size<n&&p->rlink!=(*pav); p=p->rlink);//跳出循环,首先排除p为空和p指向的空闲块容量小于 n 的情况if (!p ||p->size<n) {return NULL;}else{//指针f指向p空闲块的foot域f=FootLoc(p);//调整pav指针的位置,为下次分配做准备(*pav)=p->rlink;//如果该空闲块的存储大小比 n 大,比 n+e 小,负责第一种情况,将 p 指向的空闲块全部分配给用户if (p->size-n <= e) {if ((*pav)==p) {pav=NULL;}else{//全部分配用户,即从可利用空间表中删除 p 空闲块(*pav)->llink=p->llink;p->llink->rlink=(*pav);}//同时调整head域和foot域中的tag值p->tag=f->tag=1;}//否则,从p空闲块中拿出 大小为 n 的连续空间分配给用户,同时更新p剩余存储块中的信息。else{//更改分配块foot域的信息f->tag=1;p->size-=n;//f指针指向剩余空闲块 p 的底部f=FootLoc(p);f->tag=0;   f->uplink=p;p=f+1;//p指向的是分配给用户的块的head域,也就是该块的首地址p->tag=1;   p->size=n;}return p;}
}

【 3. 回收算法 】

  • 问题描述
    在用户活动完成,系统需要立即回收被用户占用的存储空间,以备新的用户使用。回收算法中需要解决的问题是:在若干次分配操作后,可利用空间块中会产生很多存储空间很小以致无法使用的空闲块。但是经过回收用户释放的空间后,可利用空间表中 可能含有地址相邻的空闲块,回收算法需要 将这些地址相邻的空闲块合并为大的空闲块供新的用户使用
  • 合并空闲块有 3 种情况:
    • 该空闲块的左边有相邻的空闲块可以进行合并;
    • 该空闲块的右边用相邻的空闲块可以进行合并;
    • 该空闲块的左右两侧都有相邻的空闲块可以进行合并;
  • 判断当前空闲块左右两侧是否为空闲块的方法是:
    对于当前空闲块 p ,p-1 就是相邻的低地址处的空闲块的 foot 域,如果 foot 域中的 tag 值为 0 ,表明其为空闲块; p+p->size 表示的是高地址处的块的 head 域,如果 head 域中的 tag 值为 0,表明其为空闲块。

3.1 空闲块两侧是占用块

  • 如果当前空闲块的左右两侧都不是空闲块,而是占用块,此种情况下只需要 将新的空闲块按照相应的规则(头部拟合法随意插入,其它两种方法在对应位置插入)插入到可利用空间表 中即可。
  • C 实现:
//设定p指针指向的为用户释放的空闲块
p->tag=0;
//f指针指向p空闲块的foot域
Space f=FootLoc(p);
f->uplink=p;
f->tag=0;
//如果pav指针不存在,证明可利用空间表为空,此时设置p为头指针,并重新建立双向循环链表
if (!pav) {pav=p->llink=p->rlink=p;
}else{//否则,在p空闲块插入到pav指向的空闲块的左侧Space q=pav->llink;p->rlink=pav;p->llink=q;q->rlink=pav->llink=p;pav=p;
}

3.2 空闲块左侧是空闲块

  • 如果该空闲块的左侧相邻的块为空闲块,右侧为占用块,处理的方法是:只需要 更改左侧空闲块中的 size 的大小,并重新设置左侧空闲块的 foot 域 即可(如下图所示)。
    在这里插入图片描述
  • C 实现:
//常量 n 表示当前空闲块的存储大小
int n=p->size;
Space s=(p-1)->uplink;//p-1 为当前块的左侧块的foot域,foot域中的uplink指向的就是左侧块的首地址,s指针代表的是当前块的左侧存储块
s->size+=n;//设置左侧存储块的存储容量
Space f=p+n-1;//f指针指向的是空闲块 p 的foot域
f->uplink=s;//这是foot域的uplink指针重新指向合并后的存储空间的首地址
f->tag=0;//设置foot域的tag标记为空闲块

3.3 空闲块右侧是空闲块

  • 如果用户释放的内存块的相邻左侧为占用块,右侧为空闲块,处理的方法为:将用户释放掉的存储块替换掉右侧的空闲块,同时更改存储块的 size 和右侧空闲块的 uplink 指针的指向(如下图所示)。
    在这里插入图片描述
  • C 实现:
Space t=p+p->size;//t指针指向右侧空闲块的首地址
p->tag=0;//初始化head域的tag值为0
//找到t右侧空闲块的前驱结点和后继结点,用当前释放的空闲块替换右侧空闲块
Space q=t->llink;
p->llink=q; q->rlink=p;
Space q1=t->rlink;
p->rlink=q1; q1->llink=p;
//更新释放块的size的值
p->size+=t->size;
//更改合并后的foot域的uplink指针的指向
Space f=FootLoc(t);
f->uplink=p;

3.3 空闲块两侧是空闲块

  • 如果当前用户释放掉的空闲块,物理位置上相邻的左右两侧的内存块全部为空闲块,需要将 3 个空闲块合并为一个更大的块,操作的过程为:更新左侧空闲块的 size 的值,同时在可利用空间表中摘除右侧空闲块,最后更新合并后的大的空闲块的 foot 域
    此情况和只有左侧有空闲块的情况雷同,唯一的不同点是多了一步摘除右侧相邻空闲块结点的操作。
  • C 实现:
int n=p->size;
Space s=(p-1)->uplink;//找到释放内存块物理位置相邻的低地址的空闲块
Space t=p+p->size;//找到物理位置相邻的高地址处的空闲块
s->size+=n+t->size;//更新左侧空闲块的size的值
//从可利用空间表中摘除右侧空闲块
Space q=t->llink;
Space q1=t->rlink;
q->rlink=q1;
q1->llink=q;
//更新合并后的空闲块的uplink指针的指向
Space f=FootLoc(t);
f->uplink=s;

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

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

相关文章

Vue transition使用

// 单元素、单组件 出场 入场 动画 // 入场&#xff1a;从隐藏态到显示 // 出场&#xff1a;从显示态到隐藏 <style>/*过渡 动画的封装*//* 入场*//*开始*/.v-enter-from {opacity: 0;}/*整个过程怎么执行*/.v-enter-active {transition: opacity 3s ease-out;}/*结束*/.…

用PowerPoint创建毛笔字书写动画

先看看下面这个毛笔字书写动画&#xff1a; 这个动画是用PowerPoint创建的。下面介绍创建过程。 1、在任何一款矢量图片编辑软件中创建一个图片&#xff0c;用文字工具输入文字内容。我用的是InkScape。排好版后将图片保存为.svg格式的矢量图片文件。 2、打开PowerPoint&…

x264 编码器 x264_macroblock_encode 函数

x264 264是一个开源的视频编码库,用于将视频压缩为H.264/AVC(Advanced Video Coding)格式。它是一种广泛使用的视频编码标准,能够提供高质量的视频压缩和较低的比特率。x264库提供了一个编码器,可以将原始视频序列转换为H.264/AVC压缩的比特流。它实现了各种H.264编码算法…

【C++泛型编程】(二)标准模板库 STL

文章目录 标准模板库 STL容器算法迭代器仿函数/函数对象适配器分配器示例 标准模板库 STL C 的标准模板库&#xff08;Standard Template Library&#xff0c;STL&#xff09;旨在通过模板化的设计&#xff0c;提供一种通用的编程模式&#xff0c;使程序员能方便地实现和扩展各…

暴雨发布大模型专用分布式全闪存储

近日&#xff0c;暴雨信息发布为大模型专门优化的分布式全闪存储AVERSE系列。该系列依托暴雨信息自研分布式文件系统&#xff0c;搭载新一代数据加速引擎Xdata&#xff0c;通过盘控协同、GPU直访存储、全局一致性缓存等技术为AI大模型数据归集、训练、数据归档与管理等阶段提供…

在Python中安装和使用pandas库

在Python中安装和使用pandas库是一个相对简单的过程。以下是具体的步骤&#xff1a; 安装pandas库 你可以使用Python的包管理器pip来安装pandas。打开你的命令行工具&#xff08;在Windows上可能是CMD或PowerShell&#xff0c;在macOS或Linux上可能是Terminal&#xff09;&am…

看完这篇文章我奶奶都懂Opentracing了 (二)

二. 概念分析 1. Span和SpanContext 结合上述示例&#xff0c;我们从Span开始入手来进行概念分析&#xff0c;但是说在最前面&#xff0c;Span在不同的分布式链路实现中&#xff0c;其定义是不全一样的&#xff0c;尽管Opentracing已经进行了概念的统一&#xff0c;但是具体到…

1-1ARM开发环境搭建(GD32)

1:安装MDK最好是5.27以及以上版本&#xff0c;避免后续学习中出现相关错误 2&#xff1a;安装芯片支持包 双击安装即可&#xff0c;也可以是默认路径&#xff0c;也可以自己更改路径 3&#xff1a;安装jlink下载器驱动&#xff08;下载调试器&#xff09; 具体安装步骤如下所示…

一键解密,网络安全神器现已问世!

一、简介 当前版本V1.1这款工具是一款功能强大的网络安全综合工具&#xff0c;旨在为安全从业者、红蓝对抗人员和网络安全爱好者提供全面的网络安全解决方案。它集成了多种实用功能&#xff0c;包括解密、分析、扫描、溯源等&#xff0c;为用户提供了便捷的操作界面和丰富的功…

RTSP(Real Time Streaming Protocol)协议

RTSP&#xff08;Real Time Streaming Protocol&#xff09;是一种网络流媒体协议&#xff0c;用于建立和控制媒体服务器上的一个或多个时间同步的流媒体会话。RTSP 并不直接传输流媒体数据&#xff0c;而是为流媒体服务器提供了一种控制和选择流媒体的能力。 RTSP 是在 HTTP 基…

1456. 定长子串中元音的最大数目C++

给你字符串 s 和整数 k 。 请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。 英文中的 元音字母 为&#xff08;a, e, i, o, u&#xff09;。 示例 1&#xff1a; 输入&#xff1a;s "abciiidef", k 3 输出&#xff1a;3 解释&#xff1a…

一个好用的MQTT客户端软件

软件功能如下&#xff0c;实现的协议版本是 3.1.1 仅实现了常用的 CONNECT , PUBLISH , SUBSCRIBE 及相应的应答报文。支持以 Hex 格式显示接收的原始报文&#xff08;方便初学者学习&#xff09;。支持所有字段的自定义配置。支持保存与加载配置文件。 软件界面如下所示&…

NumPy 数组切片及数据类型介绍

NumPy 数组切片 NumPy 数组切片用于从数组中提取子集。它类似于 Python 中的列表切片&#xff0c;但支持多维数组。 一维数组切片 要从一维数组中提取子集&#xff0c;可以使用方括号 [] 并指定切片。切片由起始索引、结束索引和可选步长组成&#xff0c;用冒号 : 分隔。 语…

ESP32 IDF linux下开发环境搭建

文章目录 介绍升级Python环境下载Python包配置编译环境及安装Python设置环境变量 ESPIDF环境搭建下载esp-idf 代码编译等待下载烧录成功查看串口打印 介绍 esp32 官方文档给的不是特别详细 参考多方资料 最后才完成开发 主要问题在于github下载的很慢本教程适用于ubuntu deban…

Vue生命周期都有哪些?

定义 Vue的生命周期就是实例从创建到销毁的一个过程&#xff0c;即从创建、初始化数据、编译模板、挂载Dom($el)->渲染、更新->渲染&#xff0c;卸载等一系列的过程。el是挂载点如<div id"app"></div>。 Vue的生命周期分为八个阶段 1.beforeCreate…

关于实体类注解@Data、@EqualsAndHashCode(callSuper = true)、@Accessors(chain = true)的作用

笔记&#xff1a;都是lombook插件的注解&#xff0c;作用是简化优化代码等&#xff0c;比如getter、setter&#xff0c;一般三者连用能避免一些如继承类的导致的一些坑&#xff0c;比如equal()方法的错误&#xff0c;具体用法可查阅每个注解及属性的作用。 Accessors(chain tr…

OpenAPI 4 版本推出后会带来怎样的行业变革?

随着数字化浪潮的来临&#xff0c;软件开发与应用程序接口&#xff08;API&#xff09;在现今社会的商业及技术领域变得至关重要。API如同不同软件和服务之间的纽带&#xff0c;它将数据的流动和多个系统的无缝对接变为可能&#xff0c;极大地促进了技术的快速进步与应用的广泛…

ubuntu20安装colmap

系统环境 ubuntu20 &#xff0c;cuda11.8 &#xff0c;也安装了anaconda。因为根据colmap的官方文档说的&#xff0c;如果根据apt-get安装的话&#xff0c;默认是非cuda版本的&#xff0c;而我觉得既然都安装了cuda11.8了&#xff0c;自然也要安装cuda版本的colmap。 安装步骤…

2022 年全国职业院校技能大赛高职组云计算赛项试卷(容器云)

#需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私聊博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私聊博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包…

Flutter开发Dart中的队列(Queue)

文章目录 Dart中的队列&#xff08;Queue&#xff09;基本操作示例队列的类型队列的应用总结 Dart中的队列&#xff08;Queue&#xff09; 队列是一种抽象的数据结构&#xff0c;遵循“先进先出”&#xff08;FIFO&#xff09;的原则。这意味着最早添加的元素将首先被移除。队…