首先对基于隐式空闲链表,使用立即边界标记合并方式实现的简单分配器进行分析。实验参考资料

隐式空闲链表的恒定形式如下图所示:

其结构为: 第一个字是不使用的填充字,使得双字的序言块(prologue block)边界对齐。这个特殊的序言块是一个8字节的分配块,仅由一个头部和一个脚部组成。序言块后面紧跟着零个或多个malloc创建free调用的普通块,在初始化时,这个块接近堆的大小。在堆的尾部是一个特殊的大小为零已分配的结尾块(epilogue block),只由一个头部组成。在初始化(mm_init)的时候,序言块、结尾块以及之间的大的空闲块(具有头部和尾部,是由extend_heap函数创建的)被创建,序言块永远不会释放。
(1)获得堆中空闲块的起始地址

void *mem_sbrk(int incr) {char *old_brk=mem_brk; if((incr<0)||((mem_brk+incr)>mem_max_addr)) {errno=ENOMEM;fprintf(stderr,"ERROR: mem_sbrk failed. Ran out of memory...\n");return (void *) -1;}mem_brk+=incr;return (void *)old_brk;
}

(2)定义具体地址访问操作实现方法

/*创建基本常量和操作,宏函数的名字应该能体现出函数的行为是什么*/
#define WSIZE 4 //一个字的大小,四个字节
#define DSIZE 8 //分配器的返回的块是8字节对齐的,块就是一次分配的大小,例如malloc(3),将返回块的大小是8
#define CHUNKSIZE (1<<12) //最大的空闲块#define MAX(x,y) ((x) > (y)? (x) : (y))/*将头部或尾部中保存的块的大小和3位标记位进行合并*/
#define PACK(size,alloc) ((size)|(alloc))/*从地址p读或者写一个四字节的量*/
#define GET(p) (*(unsigned int *) (p))
#define PUT(p,val) (*(unsigned int *) (p)=(val))/*从地址p获得块的大小以及查看块是已分配还是空闲的*/
#define GET_SIZE(p) (GET(p) & -0x7)
#define GET_ALLOC(p) (GET(p) & 0x1)/*从空闲块(有效载荷)地址获得头部地址或者尾部地址*/
#define HDRP(bp) ((char *)(bp) - WSIZE)
#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)//这里减DSIZE是因为加上GET_SIZE,多加了一个头部                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                /*通过空闲块的地址bp,计算下一个或前一个块的地址*/
#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE)))//注意:这里的括号是个易错点,(char *)(bp) - WSIZE是一个整体注意加括号,总之是一个整体的通通加括号确定计算,依靠优先级在这里不好使
#define PREV_BLKP(bp) ((char *)(bp)-GET_SIZE(((char *)(bp) - DSIZE)))

(3)创建初始空闲链表

int mm_init() {if((heap_listp=mem_sbrk(4*WSIZE))==(void *)-1) {//看分配是否越界return -1;}PUT(heap_listp,0);//从地址heap_listp写入四个字节,内容为0PUT(heap_listp+(1*WSIZE),PACK(DSIZE,1));//填入序言块头部的内容PUT(heap_listp+(2*WSIZE),PACK(DSIZE,1));//填入序言块尾部的内容PUT(heap_listp+(3*WSIZE),PACK(0,1));//结尾块头部的内容heap_listp+=(2*WSIZE);//初始化后heap_listp的最终位置//最大的空闲块被创建if(extend_heap(CHUNKSIZE/WSIZE)==NULL)return -1;return 0;
}
static void *extend_heap(size_t words) {char *bp;size_t size;/*强行进行偶数个字分配*/size=(words%2) ? (words+1)*WSIZE : words*WSIZE;if((long) (bp=mem_sbrk(size))==-1)//申请的区域超出最大堆的大小return NULL;/*对空闲块填充必要信息*/PUT(HDRP(bp),PACK(size,0));PUT(FTRP(bp),PACK(size,0));PUT(HDRP(NEXT_BLKP(bp)),PACK(0,1));/*采用立即边界合并方式:在每次一个块被释放时就合并所有的相邻块*/return coalesce(bp);
}


释放和合并块

void mm_free(void *bp) {/*获取分配空间的大小,将标记位进行清零*/size_t size=GET_SIZE(HDRP(bp));PUT(HDRP(bp),PACK(size,0));PUT(FTRP(bp),PACK(size,0));//释放后立即检查能不能合并coalesce(bp);
}static void *coalesce(void *bp) {/*获取前后块的标记位信息*/size_t prev_alloc=GET_ALLOC(FTRP(PREV_BLKP(bp)));size_t next_alloc=GET_ALLOC(HDRP(NEXT_BLKP(bp)));size_t size=GET_SIZE(HDRP(bp));//当前块的大小/*合并块的四种情况*/if(prev_alloc&&next_alloc) {//前后块都已分配,不进行合并return bp;} else if(prev_alloc&&!next_alloc) {//后块没有分配size+=GET_SIZE(HDRP(NEXT_BLKP(bp)));PUT(HDRP(bp),PACK(size,0));PUT(FTRP(bp),PACK(size,0));} else if(!prev_alloc&&next_alloc) {//前块没有分配size+=GET_SIZE(HDRP(PREV_BLKP(bp)));PUT(FTRP(bp),PACK(size,0));PUT(HDRP(PREV_BLKP(bp)),PACK(size,0));bp=PREV_BLKP(bp);} else {//前后都没有分配size+=GET_SIZE(HDRP(PREV_BLKP(bp)))+GET_SIZE(FTRP(NEXT_BLKP(bp)));PUT(HDRP(PREV_BLKP(bp)),PACK(size,0));PUT(FTRP(NEXT_BLKP(bp)),PACK(size,0));bp=PREV_BLKP(bp);}return bp;
}

malloc lab相关推荐

  1. Lab7 Malloc Lab

    Lab7 Malloc Lab 写在前言:这个实验的来源是CSAPP官网:CSAPP Labs ,如果感兴趣的话,可以点击这个链接

  2. 《深入理解计算机系统》(CSAPP)实验七 —— Malloc Lab

    文章目录 隐式空闲链表 分离的空闲链表 显示空闲链表 1. 实验目的 2. 背景知识 3. Implicit list mm_init extend_heap mm_malloc find_fit p ...

  3. CSAPP Lab2 实验记录 ---- Bomb Lab(Phase 1 - Phase 6详细解答 + Secret Phase彩蛋解析)

    文章目录 Lab 总结博客链接 实验前提引子 实验需要指令及准备 Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6 Phase Secret(彩蛋Phas ...

  4. 深入理解计算机系统(CSAPP)含lab详解 完结

    文章目录 深入理解计算机操作系统-第一章 1.1 信息就是位 + 上下文 1.2 程序被其他程序翻译成不同的格式 1.3 了解编译系统如何工作是大有益处的 1.4 处理器读并解释储存在内存中的指令 1 ...

  5. CSAPP:MallocLab

    Malloc Lab 做什么? 实现一个内存分配器 怎么做? 非常建议看完书后,自己写一遍,进步非常大,可以检测出你哪块理解不够深刻,可以将这块知识点吃的很透彻.在遇到瓶颈的时候看看人家怎么写的,不然 ...

  6. UNP 学习笔记 5:高级 IO 与 IO 复用

    可惜 UNP 和 APUE 不讲 EPOLL,UNP 的重点内容可能快看完了,之后 UNPv1 就做参考书了,然后之后的 Linux 服务器编程就全是搞 APUE 和 Linux 编程的书了,看来之后 ...

  7. C++ 学习路线:快速入门到进阶

    C/C++ 是一门底层.细粒度.功能强大.学习曲线陡峭的语言,虽然在Python等新语言的冲击下略显龙钟老态,但随着AIoT设备的兴起,以及C++社区不断推出新的版本,这门语言又重新焕发了生机. 本文 ...

  8. 后端集训营|放个大招

    后端技术方向未来发展 1 传统互联网后台服务器系统,都是海量数据处理系统,都是经过单机性能优化,然后再靠堆机器,当发展到一定程度,就开始降本增效,需要极致的性能优化来减少物理成本,大厂会招聘技术高手. ...

  9. CSAPP(CMU 15-213):Lab6 Malloclab详解

    # 前言 本系列文章意在记录答主学习CSAPP Lab的过程,也旨在可以帮助后人一二,欢迎大家指正! tips:本lab主要是为了体验应用程序如何使用和管理虚拟内存,写一个动态存储分配器(dynami ...

最新文章

  1. JAVA多线程总结(笔记)
  2. mysql in 子查询优化_mysql in 子查询 容易优化
  3. 起到的C++是中间层的作用
  4. python实战1.0——爬取知乎某问题下的回复
  5. 脱离 Windows 完全使用 Linux你花了多少时间适应?
  6. Java数据结构:稀疏数组(Sparse Array)的创建和文件存取
  7. 英雄传奇-6.专用浏览器打不开.黑屏.白屏.插件丢失等怎么解决
  8. Cisco 安全设备管理工具:SDM
  9. 鲜卑族的由来与现在的分布
  10. 一个点的经度和纬度,以这个点为圆心,1000米为半径,最大的经度和纬度,最小的经度和纬度
  11. 记录一次GeoTIFF文件二进制源码阅读
  12. 英语海报简笔php匹配img画,简单英语海报图片手绘,一年级英语海报图片 手绘?...
  13. 睡眠手环APP开发优势特点
  14. Conflux 的自我进化:从 DAG 到树图| 对话伍鸣
  15. YUI 3 学习笔记:loader
  16. 信号之零输入和零状态响应
  17. c3p0-config.xml配置文件的那些事
  18. 感性负载产生负压的影响分析
  19. 00后确实卷,公司新来的卷王,我们这帮老油条真干不过...
  20. 如何用代码实现图片,音频视频的复制粘贴

热门文章

  1. 超详细教程-Django使用邮箱发送验证码
  2. 计算机服务启动按钮显示灰色,win10系统自带还原按钮显示灰色无法还原的详细办法...
  3. jQuery.lazyload懒加载
  4. PCA的Matlab实现与分析
  5. java日期格式 hh HH kk
  6. Cesium画个雷达四凌锥体
  7. 【Axure视频教程】中继器图文卡片
  8. 2022年4月总结,专注技术领域,沉淀自己,打造个人IP
  9. 如何成为一个自律的人?这5本书里藏着你想要的答案
  10. 【众筹】百问网DShanMCU-Mio开源掌机(爻-澪)项目,完美支持运行10多个模拟器!