当前位置: 首页 > 编程日记 > 正文

内存管理器(二)边界标识法

边界标识算法

前言

首先说明,我们这里的内存管理器主要是以模拟各种内存分配算法为主,从内存申请一片内存然后根据我们所选定的数据结构和算法,实现程序的堆空间的分配,至于内存分配详情我们会在Linux内核内存管理的简单分析中探讨。

这个算法是什么

边界标识法是操作系统中用以进行动态分配的一种存储管理的方法,系统将所有的空闲块链接在一个双重循环链表结构中;分配可以按照首次匹配,最佳匹配方法执行,其次个人觉得先学这个算法然后在学伙伴算法能更简单点吧。

这个算法的特点

在每个内存区的头部和底部两个边界上分别设有标识,以标识该区域的占用块和空闲块,使得在回收用户释放的空闲块时易于判别在物理上位置上与其相邻的内存区域是否为空闲块,以便将所有地址连续的空闲存储区组合成一个尽可能更大的空闲块。

图解这个算法

数据结构

这就是抽象的链表节点,分别由头head,空间(内存块),尾tail ,组成。
其中表头由4个部分组成。
llink : 这个数据结构主体是循环链表,所以这个指针指向前一个节点。
tag : 标示位:1标示为已分配块,0标示未分配块。
size : 标示这个节点的大小(包括头部和尾部)。
rlink : 由于是双向循环链表,这个指针指向后一个节点。

表尾由2个部分组成:
uplink : 指向本节点的头部。
tag : 同上标示分配情况。

边界标示法

其中这些节点的链接形式如图所示,基础是双向循环链表并且包含上述结构体。

节点数据结构

typedef struct WORD{   //WORD :内存字类型union{WORD *llink ; //头和尾都是同一个节点WORD *uplink;};int tag ; //块标志,0:空闲,1:占用int size; //块大小WORD *rlink; //指向后继节点OtherType other; //其它部分}WORD,head,foot,*Space;

这个算法其他一些要注意的地方

  1. 假设每次需要找m 个大小,但是我们每次都分配n 给它,那么久而久之,就会有很多的m-n 个空间散落于链表中,所以我们需要设置一个标准值e,当m-n <= e 的时候,就将m 的空闲整块分配给它,反之,我们就分配想当需求大小的空间。
  2. 如果收每一次都从头开始寻找就是首次匹配,由于已经进行多次,必然前边会聚集较多的小块,所以我们应当每次分配一次就将,表头指向它已经分配的后边的一个节点,这样就能基本保证每一次的进行首次匹配的效果了。

回收算法:

回收的思想很简单,根据它前后块的不同,总共有4中情况。
1.前后都已经占用
直接将内存块插入。
2.前一个已经被占用,后一个没有被占用。
我们直接将后一个,和待回收的块合并成一个完整的块。
3前一个没有被占用,后一个已经被占用。
我们将前一个和待回收的块合并成一个完整的块。
4前一个与后一个都没有被占用。
我们将三个块全部合并成一个完整的未分配块。

下面就来看一个使用边界标识法的空间管理简例

#include<stdio.h>
#include<stdlib.h>#define MAXSIZE    1000
#define ALLOC_MIN  100 
#define FootLoc(p)  (p+(p->size) - 1)typedef struct WORD{    //WORD:内存字类型union {                //头和尾都指向同一个位置使用联合体struct WORD *llink;struct WORD *uplink;};int tag ; //块标识:1:占用 0: 空闲int size ; //块的大小struct WORD *rlink;   //指向后继节点// OtherType other; //字的其他部分这里暂时用不到}*Space;Space user[MAXSIZE] = {NULL} ; //用户空间数组int usCount = 0;Space AllocBoundTag(Space *pav,int n){Space p = * pav;if(NULL == p){printf("The memory is NULL \n");return NULL;}for(p;p != NULL && p->size < n && p->rlink != *pav; p = p->rlink ){if(p == NULL || p->size < n){printf("error is :%d\n",__LINE__);return NULL;}*pav = p->rlink;    //防止小的零碎空间全部集中在前边if(p->size - n > ALLOC_MIN){  // 找到可以分配的块开始分配 ,同样也为了减少碎片 ,从高位截取p,且设置新的底部p->size -= n;             //计算剩余块的大小Space foot = FootLoc(p);  //指向剩余块的底部foot->uplink = p;         //设置剩余块的底部foot->tag = 0 ;           //设置剩余块底部的标识p = foot + 1  ;           //指向分配块的头部p->size = n ;          //设置分配块的头部foot = FootLoc(p);     //指向分配块的底部p->tag = 1 ;        //设置分配块的头部foot ->tag = 1;    //同上foot->uplink = p ;}else{ //分配后剩余空间小于规定的ALLOC_MINif(p == *pav){  //如果只剩下一个空间了,清空指针*pav = NULL ;}else{ //直接分配整个块出去,虽然会浪费一部分空间Space foot = FootLoc(p);foot->tag = p->tag = 1;p->llink->rlink = p->rlink ;p->rlink->llink = p->llink ;}}}user[usCount++] = p; return p;
}void Space_init(Space * freeSpace, Space *pav){*freeSpace = (Space)malloc(sizeof(struct WORD)*(MAXSIZE + 2)); //初始化空间链表Space head = *freeSpace ;   //头指针head->tag = 1;             //设置头指针标示符head++;                    //头指针指向第一个节点head->tag = 0;             //设置第一个节点为空闲块              head->llink = head->rlink = head;  //设置循环链表head->size = MAXSIZE ;            //设置块的大小*pav = head ;                 //设置头指针    Space foot = FootLoc(head);   foot->tag = 0;foot->uplink = head ;foot++;foot->tag = 1;               //设置尾边界为已经使用}void reclaimBoundTag(Space *pav ,Space sp){Space  pre = (sp - 1)->uplink ;Space  next = sp + sp->size ;int pTag = pre->tag ;int nTag = next->tag ;           //声明两个节点,分别得到前一个和后一个节点的信息,并且记录占用情况,根据占用情况选择合并的手段if(pTag == 1 && nTag == 1 ){  //前后都是满的直接插入Space foot = FootLoc(sp);foot->tag = sp->tag = 0;if(pav == NULL){*pav = sp->llink = sp->rlink = sp;}else{sp->rlink = *pav ;sp->llink = (*pav)->llink;(*pre).llink = sp ;sp->llink->rlink = sp;*pav = sp;}}else if(pTag == 0 && nTag == 1){  // 前边的可以合并pre->size += sp->size ;Space foot = FootLoc(pre);foot->tag = 0;foot->uplink = pre;}else if(pTag == 1 && nTag == 0){  //后边的可以合并sp->llink = next->llink;sp->rlink = next->rlink;next->llink->rlink = sp ;next->rlink->llink = sp ;sp->size += next->size ;Space foot = FootLoc(sp);sp->tag = foot->tag = 0 ;foot->uplink = sp;}else{   //三个块一起合并pre->rlink = next->rlink;pre->size += sp->size + next->size;Space foot = FootLoc(pre);foot->uplink = pre ;}int i ;for(i = 0;i < usCount ;i++){if(sp == user[i]){user[i] = NULL;}}
}void print(Space s){printf("The head is %0x SIZE: %d \n pre is %0x ,next is %0x\n",s,s->size,s->llink,s->rlink);
}void print_space(Space pav){if(pav != NULL){printf("you an use the list:\n");Space pos = pav;for(pos = pos->rlink;pos != pav;pos = pos->rlink){print(pos);}}printf("_____________________________\n");int i ;for(i = 0;i< usCount ;i++){Space us = user[i];if(us){printf("the head is %0x  SIZE is %d\n",us,us->size);}}}int main(){Space freeSpace = NULL;Space pav = NULL;Space_init(&freeSpace,&pav);print(pav);printf("malloc a 300 and 300 \n");Space m3 = AllocBoundTag(&pav,300);print_space(pav);Space t3 = AllocBoundTag(&pav,300);print_space(pav);printf("free 300 \n");reclaimBoundTag(&pav,m3);print_space(pav);return 0;
}

参考资料:
《CSAPP》
《数据结构(严尉敏)》
http://blog.csdn.net/fuming0210sc/

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/zmrlinux/p/4921381.html

相关文章:

XDOC Office Server 开源了,Office文档完美转换为PDF

百度智能云 云生态狂欢季 热门云产品1折起>>> 项目地址&#xff1a;https://gitee.com/xdoc/xoffice XDOC是一个文档自动化平台&#xff0c;提供免费的Office文档生成服务。有用户提出要PDF格式&#xff0c;便于阅读、发布。在尝试了OpenOffice、WPS、微软Office、P…

js的defer属性

js的defer属性说明&#xff1a;<script src"js.js" type"text/javascript defer"defer"/>中defer的作用 给外链的js脚本添加defer"defer" 或 defer"true",使用defer属性可以让脚本在整个页面装载完成之后再解析&#xff0c…

怎么读取java文件,Java怎么读取文件

当前位置:我的异常网 J2SE Java怎么读取文件Java怎么读取文件www.myexceptions.net 网友分享于&#xff1a;2013-12-20 浏览&#xff1a;60次Java如何读取文件?源文件如下,小弟没有学过Java,下面是一段JAVA用RSA加密字符串的程序,命令行的形式是Java PublicExample ABC…

Android环境变量的设置(详细图解版)

Android环境变量的设置&#xff08;详细图解版&#xff09; 转载于:https://www.cnblogs.com/zhujiabin/p/4875182.html

用加密货币连接业务的6种方法

如今&#xff0c;区块链技术和加密货币已经变得更加接近传统业务。在某些情况下&#xff0c;商人们能够找到一种将传 统商业与新技术相结合的有价值的模式。事实上&#xff0c;进入加密货币市场有很多选择&#xff0c;本文将讨论6种主 要的合作方式。 创建加密货币平台是为了完…

extjs grid renderer用法

renderer可以格式化该列显示的数据格式或者按照你自定义的脚本显示最终数据样子&#xff08;我目前是这么理解的&#xff09; 先看下renderer: function()里的参数 var cm new Ext.grid.ColumnModel([new Ext.grid.RowNumberer(),sm,{header:商品名称, dataIndex: name,render…

java50车架适合身高,【经验分享】身高与车架的选择

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼车架的长度&#xff1a;骑在车上&#xff0c;在正常握把时&#xff0c;眼睛、把立前端和前轮花鼓三点一线则说明车架长度正好&#xff0c;否则可通过更换不同长度的把立来调整长度。在Airborne网站上看到了度量身体个部位长度和计算…

从Android界面开发谈起(转)

原文地址&#xff1a;http://blog.csdn.net/nieweilin/article/details/5967815 这篇文章没有打算有一个很好的逻辑去介绍android的某个方面&#xff0c;全盘大致上就是我接触、了解android的ui开发后到现在的一些感想以及个人理解吧&#xff01; 全文可能会涉及到java、androi…

Android笔记之使用LocationManager获取经纬度

LocationManager.getLastKnownLocation(String provider)有可能返回null&#xff0c;概率还挺高 findViewById(R.id.llMain).setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {AndPermission.with(MainActivity.this).runtime().permissi…

Java虚拟机类加载机制

虚拟机类加载机制&#xff1a;虚拟机把描述类的数据从class文件加载到内存&#xff0c;并对数据进行校验、转换解析和初始化&#xff0c;最终形成可以被虚拟机直接使用的Java类型。 Java语言里&#xff0c;类型的加载和连接过程是在程序运行期间完成的。 类的生命周期&#xff…

dw8与mysql的连接,VS2019连接mysql8.0数据库的教程图文详解

1.首先准备好vs2019以及mysql数据库&#xff0c;两者都可以去官网下载&#xff0c;我们直接描述连接过程。2.连接&#xff1a;第一步&#xff1a;打开mysql的安装目录&#xff0c;我本地的安装目录如下&#xff1a;(注意是否有include和lib文件夹)第二步&#xff1a;打开vs2019…

IOS中打开应用实现检查更新的功能

//检查更新页面- (void)Renew{ NSDictionary *infoDic [[NSBundle mainBundle]infoDictionary]; NSString *version [infoDic valueForKey:"CFBundleShortVersionString"]; NSString *ipstr [NSObject deviceIPAdress]; NSString *p…

CSS3边框背景-边框背景(-border-image)

另一个令人兴奋的新特征是边框图片。有了这项功能您可以定义一个图像被用来代替正常的边框的一个组成部分。这项功能实际上是分成了几个属性&#xff1a;边框和边框角的形象。这两个值是&#xff1a; border-image: border-top-imageborder-right-imageborder-bottom-imagebord…

Promise的实例用法

设定函数 function chiFan() {return new Promise(function(resolve, reject) {console.log("chiFan");}) }function shuiJiao() {return new Promise(function(resolve, reject) {console.log("shuiJiao");}) }function daDouDou() {return new Promise(f…

php文件夹列表,php获取文件夹下面的文件列表和文件夹列表

function getDir($dir) {$dirArray[] NULL;if (false ! ($handle opendir( $dir ))) {$i0;while ( false ! ($file readdir( $handle )) ) {//去掉"“.”、“..”以及带“.xxx”后缀的文件if ($file ! "." && $file ! ".."&&!strp…

SharePoint API测试系列——Records.BypassLocks测试

转载请注明出自天外归云的博客园&#xff1a;http://www.cnblogs.com/LanTianYou/ 对于SharePoint中已经是Record的Item&#xff0c;我们想要修改他的属性&#xff0c;这在UI界面是无法完成的&#xff1a; 这时需要通过Records.BypassLocks API来完成。设计一个tool&#xff0c…

我对自动化测试工程师招聘的建议

给以前公司招聘人员做的一个培训:/Files/killmyday/2011年PTA测试培训课件.zip 转载于:https://www.cnblogs.com/killmyday/archive/2012/04/15/2450108.html

解决请求中400的问题

具体报错&#xff1a;2019-03-19 12:01:35,097 - request - DEBUG - json_data: {timestamp: 1552968086846, status: 400, error: Bad Request, exception: org.springframework.http.converter.HttpMessageNotReadableException, message: "JSON parse error: Unrecogni…

java 中lock,java中lock获取锁的四种方法

在java接口中会存放着许多方法&#xff0c;方便线程使用时的直接调用。对于lock接口大家都不陌生&#xff0c;我们已经初步对概念进行了理解。那么在获取锁的方法上想必还不是很清楚。下面我们就lock获取锁的四种方法分别进行概念的介绍&#xff0c;然后就其中的tryLock()方法带…

RadASM的测试工程!

RadASM已经安装完毕了&#xff0c;是否可以正常工作了呢&#xff1f;我们通过创建一个工程来测试一下&#xff0c;下面就是创建这个测试工程的过程&#xff1a; 1&#xff0c; 2&#xff0c; 3&#xff0c; 4&#xff0c; 5&#xff0c; 6&#xff0c; 7&#xff0c; 8&#xf…

单片机 键盘

键盘分类&#xff1a; &#xff08;1&#xff09;编码键盘 键盘上闭合键的识别由专门的硬件编码器实现&#xff0c;并产生键编码号或键值的称为编码键盘&#xff0c;如计算 机键盘。 &#xff08;2&#xff09;非编码键盘 靠软件编程来识别的键盘称为非…

React typescript issue

多个输入框发生变化时&#xff0c;setState: this.setState({[e.target.name]: e.target.value} as componentState) 转载于:https://www.cnblogs.com/Nyan-Workflow-FC/p/10561058.html

java 匿名list,java创造匿名对象的两种方法

在java中有时候需要一些匿名对象的使用。可能有些小伙伴拿还不会创造&#xff0c;其实我们在学习一些方法时都或多或少的接触过。本篇所要讲到的创造匿名对象总结了两种方法&#xff0c;分别是静态工具方法和Lambda表达式&#xff0c;我们会在下文中为大家进行分析和实例代码展…

apk签名验证机制

声明&#xff1a; 1.本帖转载自&#xff1a;http://riusksk.blogbus.com/logs/272154406.html&#xff0c;仅供自用&#xff0c;勿喷 2.欢迎交流学习 签名后的APK&#xff0c;在/META-INF目录下会生成以下3个文件&#xff1a; MANIFEST.MF&#xff1a;保存除META-INF文件以外其…

spring cloud微服务分布式云架构--hystrix的使用

hystrix主要作用在服务消费者&#xff0c;进行应用的保护&#xff0c;当请求的服务请求超时时&#xff0c;做出相应的处理&#xff0c;避免客户端一直进行请求等待&#xff0c;避免在高并发的情况出现服务器死机&#xff08;请求过多&#xff0c;内存不足&#xff09; 接下来的…

JSP项目目录中每个文件夹及配置文件的作用

/WEB-INF目录&#xff1a;Web应用应用部署目录&#xff0c;浏览客户是看不到该目录下的文件的&#xff0c;该目录下的文件专供Web服务器专用。web.xml&#xff1a;部署描述文件&#xff0c;/WEB-INF目录下最重要的文件&#xff0c;它描述了程序的部署、配置信息&#xff0c;为W…

java里锛是什么意思,java实验总结

p3person.newperson("jane", 13, f);System.out.println(p1);System.out.println(p2);System.out.println(p3);}}1. 设计一个数据单元类DataUnit, 它包含学号(Number)和姓名(Name)两个数据成员。2. 设计两个线程&#xff0c;一个线程往数据单元里写信息&#xff0c;一…

c调用python

tables.py global gtablesgtables { 1001:"张鲁p", 1002:"凌p", 2001:"李进a", 2002:"vb" } from tables import gtables def get_cmd(key, value): name "0"; try: name gtables[key] …

梦美生命获1亿元A轮融资,鼎晖领投

3月20日消息&#xff0c;跨境辅助生殖医疗IVF服务的企业梦美生命&#xff08;下称&#xff1a;梦美&#xff09;已获得约1亿人民币A轮融资&#xff0c;由鼎晖领投&#xff0c;淡蓝及天使投资方开牛投资跟投&#xff0c;本轮融资主要用于人才引进以及市场推广。 梦美成立于2013…

网站锁定php文件命令,PHP文件锁定读写的一点注意_php

都说文本方式容易出现文件锁定失效等乱七八糟的问题.其实并不是失效, 而是写法有些不对.被 lock_ex 后的文件 再以read模式 fopen 的话将读到空内容!!!如果没有判断就把它作操作后再写入就出错啦....很多问题出在这里.再来补充一下如果一个文件被以write的模式fopen后并 flock(…