在做csapp的malloc实验,一开始是按照书上的隐式链表法,发现得分很低。这种方法确实很挫,需要遍历一遍以找到合适的空闲块。于是我想到《STL源码剖析》中stl的内存池,感觉应该可以用类似的方法做,因为malloc要做的事情实际就是为了防止内存碎片和减少系统调用,实际就是一个内存池。但是书上介绍的stl的内存池是没有边界区块的,也就是没办法合并空闲区块,这样可能产生过多的外部碎片。所以我最终的做法是大体上采用stl的方法,再加上边界区块,以方便合并空闲区块。

首先是根据需要的大小在freelist中找到合适的位置

  1. int getListOffset(size_t size) {
  2. size_t n = -;
  3. while((size = size>>))
  4. ++n;
  5. if(n>)
  6. return ;
  7. if(n<)
  8. return ;
  9. return n;
  10. }

freelist数组在初始化时创建,将指向空闲块的指针插入freelist的操作如下

  1. /*
  2. * insert_list - 将free block插入到相应大小的free list中, 插入位置为表头
  3. */
  4. void insert_list(void *bp)
  5. {
  6. int index;
  7. size_t size;
  8. size = GET_SIZE(HDRP(bp));
  9. index = getListOffset(size);
  10.  
  11. if (GET_PTR(heap_listp + WSIZE * index) == NULL) {
  12. PUT_PTR(heap_listp + WSIZE * index, bp);
  13. PUT_PTR(bp, NULL);
  14. PUT_PTR((unsigned int *)bp + , NULL);
  15. } else {
  16. PUT_PTR(bp, GET_PTR(heap_listp + WSIZE * index));
  17. PUT_PTR(GET_PTR(heap_listp + WSIZE * index) + , bp);
  18. PUT_PTR((unsigned int *)bp + , NULL);
  19. PUT_PTR(heap_listp + WSIZE * index, bp);
  20. }
  21. }

可以看出,空闲块的前8个字节用来存放指向freelist对应位置的指针和指向下一个相同大小的空闲块的指针。当执行malloc时,这两个指针会被清除

  1. /*
  2. * place - place the requested block at the beginning of the free block
  3. */
  4. void place(void *bp, size_t asize)
  5. {
  6. size_t csize = GET_SIZE(HDRP(bp));
  7. delete_list(bp);
  8. if ((csize - asize) >= ( * DSIZE)) {
  9. PUT(HDRP(bp), PACK(asize, ));
  10. PUT(FTRP(bp), PACK(asize, ));
  11. bp = NEXT_BLKP(bp);
  12. PUT(HDRP(bp), PACK(csize - asize, ));
  13. PUT(FTRP(bp), PACK(csize - asize, ));
  14. insert_list(bp);
  15. } else {
  16. PUT(HDRP(bp), PACK(csize, ));
  17. PUT(FTRP(bp), PACK(csize, ));
  18. }
  19. }

delete_list的实现如下

  1. /*
  2. * delete_list - 删除链表结点
  3. */
  4. void delete_list(void *bp)
  5. {
  6. int index;
  7. size_t size;
  8. size = GET_SIZE(HDRP(bp));
  9. index = getListOffset(size);
  10. if (GET_PTR(bp) == NULL && GET_PTR((unsigned int *)bp + ) == NULL) {
  11. /* 链表中唯一结点 */
  12. PUT_PTR(heap_listp + WSIZE * index, NULL);
  13. } else if (GET_PTR(bp) == NULL && GET_PTR((unsigned int *)bp + ) != NULL) {
  14. /* 链表中最后一个结点, 不是唯一一个 */
  15. PUT_PTR(GET_PTR((unsigned int *)bp + ), NULL);
  16. } else if (GET_PTR(bp) != NULL && GET_PTR((unsigned int *)bp + ) == NULL){
  17. /* 链表中第一个结点, 不是唯一一个 */
  18. PUT_PTR(heap_listp + WSIZE * index, GET_PTR(bp));
  19. PUT_PTR(GET_PTR(bp) + , NULL);
  20. } else if (GET_PTR(bp) != NULL && GET_PTR((unsigned int *)bp + ) != NULL) {
  21. /* 链表中的中间结点 */
  22. PUT_PTR(GET_PTR((unsigned int *)bp + ), GET_PTR(bp));
  23. PUT_PTR(GET_PTR(bp) + , GET_PTR((unsigned int*)bp + ));
  24. }
  25. }

这种方法很巧妙,不需要额外的空间维护freelist,需要的空间只是在初始化时创建的freelist头,其它指针只存在于空闲块中,并在malloc时删除。这个方法主要参考这里

malloc的实现的更多相关文章

  1. malloc 与 free函数详解<转载>

    malloc和free函数详解   本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...

  2. C 语言中 malloc、calloc、realloc 和free 函数的使用方法

    C标准函数库中,常见的堆上内存管理函数有malloc(), calloc(), recalloc(), free(). 之所以使用堆,是因为栈只能用来保存临时变量.局部变量和函数参数.在函数返回时,自 ...

  3. 以冒泡排序为例--malloc/free 重定向stdin stdout

    esort.c 代码如下,可关注下mallloc/free,freopen重定向的用法,排序为每轮将最小的数放在最前面: #include<stdio.h> #include<mal ...

  4. 内存动态分配之realloc(),malloc(),calloc()与new运算符

    1,malloc与free是C/C++的标准库函数,new/delete是C++的运算符,是C++面向对象的特征,它们都可用于申请动态内存和释放内存.2,对于非内部数据类型的对象而言,光用maloc/ ...

  5. 在dll里malloc/new/cvCreate分配内存,在exe里free/Releases释放内存时会出错。

    写了个程序,在DLL中用malloc分配了一块内存,但是在exe程序中释放,结果程序crash,原因就是:其原因可能是堆被损坏,这也说明 TestMySticker.exe 中或它所加载的任何 DLL ...

  6. Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解

    C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般 ...

  7. malloc与new的区别

    1.new是运算符,而malloc是库函数 2.new可以重载,可以自定义内存分配策略,甚至不做内存分配,甚至分配到非内存设备上.而malloc不能. 3.new在用于定义一个新的非内部对象的时候,默 ...

  8. new 等于 malloc加构造函数

    1.new 是c++中的操作符,malloc是c 中的一个函数 2.new 不止是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数,而malloc则只分配内存,不会进行初始化类成员 ...

  9. 关于malloc函数的动态分配问题

    malloc函数动态分配了一个整型的内存空间,让abc都指向刚申请的空间,所以只有最后一个赋值语句的值保留在了空间里 #include<stdio.h> main() { int *a,* ...

  10. 转:如何实现一个malloc

    如何实现一个malloc 转载后排版效果很差,看原文!   任何一个用过或学过C的人对malloc都不会陌生.大家都知道malloc可以分配一段连续的内存空间,并且在不再使用时可以通过free释放掉. ...

随机推荐

  1. WEB开发原则

    1.最小权限原则,只允许用户做****,而不是"不允许用户做****"2.浏览器查看的是服务端代码的执行输出的文本,除非服务器有漏洞,否则浏览者无法查看 服务端的ASPX,CS代码 ...

  2. Python3 函数式编程

    函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用.而允许使用变量的程序设计语言,由 ...

  3. REST接口规范

    参考文章 这篇文章使用不同的method代表不同操作 http://www.cnblogs.com/tommyli/p/3913018.html 实际应用中(我们过去的应用) 则是直接使用url来代表 ...

  4. 如何解决PHP中文乱码问题

    如何解决PHP中文乱码问题 一.解决HTML中中文乱码问题方法    1.在head标签里面加入UTF8编码(国际化编码):UTF-8是没有国家的编码,也就是独立于任何一种语言,任何语言都可以使用的. ...

  5. pdo如何防止 sql注入

    我们使用传统的 mysql_connect .mysql_query方法来连接查询数据库时,如果过滤不严,就有SQL注入风险,导致网站被攻击,失去控制.虽然可以用 mysql_real_escape_ ...

  6. SQLServer数据库 导出表和导入sql脚本

    1.选择需要导出表的数据库--任务---生成脚本 2.显示:生成和发布脚本窗口--简介(某些可能关闭该页面的,可以省略该步骤),点击下一步 3.显示:生成和发布脚本窗口--选择对象--按照图片操作即可 ...

  7. 定时生成bat命令

    windows下,定时生成bat的名. at 14:54 cmd /c "echo net share D=d:\ > d:d.bat" ^对>转义.

  8. TDirectory.GetDirectoryRoot获取指定目录的根目录

    使用函数: System.IOUtils.TDirectory.GetDirectoryRoot 函数定义: class function GetDirectoryRoot(const Path: s ...

  9. HBase安装inAction

    在安装Hbase之前,需要有hadoop的运行环境,关于hadoop的安装过程,请查看我之前的blog:hadoop安装笔记:或者另一个博主的超详细文章http://weixiaolu.iteye.c ...

  10. PHP错误Warning: Cannot modify header information - headers already sent by解决方法

    这篇文章主要介绍了PHP错误Warning: Cannot modify header information - headers already sent by解决方法,需要的朋友可以参考下 今天在 ...