malloc的实现
在做csapp的malloc实验,一开始是按照书上的隐式链表法,发现得分很低。这种方法确实很挫,需要遍历一遍以找到合适的空闲块。于是我想到《STL源码剖析》中stl的内存池,感觉应该可以用类似的方法做,因为malloc要做的事情实际就是为了防止内存碎片和减少系统调用,实际就是一个内存池。但是书上介绍的stl的内存池是没有边界区块的,也就是没办法合并空闲区块,这样可能产生过多的外部碎片。所以我最终的做法是大体上采用stl的方法,再加上边界区块,以方便合并空闲区块。
首先是根据需要的大小在freelist中找到合适的位置
int getListOffset(size_t size) {
size_t n = -;
while((size = size>>))
++n;
if(n>)
return ;
if(n<)
return ;
return n;
}
freelist数组在初始化时创建,将指向空闲块的指针插入freelist的操作如下
/*
* insert_list - 将free block插入到相应大小的free list中, 插入位置为表头
*/
void insert_list(void *bp)
{
int index;
size_t size;
size = GET_SIZE(HDRP(bp));
index = getListOffset(size); if (GET_PTR(heap_listp + WSIZE * index) == NULL) {
PUT_PTR(heap_listp + WSIZE * index, bp);
PUT_PTR(bp, NULL);
PUT_PTR((unsigned int *)bp + , NULL);
} else {
PUT_PTR(bp, GET_PTR(heap_listp + WSIZE * index));
PUT_PTR(GET_PTR(heap_listp + WSIZE * index) + , bp);
PUT_PTR((unsigned int *)bp + , NULL);
PUT_PTR(heap_listp + WSIZE * index, bp);
}
}
可以看出,空闲块的前8个字节用来存放指向freelist对应位置的指针和指向下一个相同大小的空闲块的指针。当执行malloc时,这两个指针会被清除
/*
* place - place the requested block at the beginning of the free block
*/
void place(void *bp, size_t asize)
{
size_t csize = GET_SIZE(HDRP(bp));
delete_list(bp);
if ((csize - asize) >= ( * DSIZE)) {
PUT(HDRP(bp), PACK(asize, ));
PUT(FTRP(bp), PACK(asize, ));
bp = NEXT_BLKP(bp);
PUT(HDRP(bp), PACK(csize - asize, ));
PUT(FTRP(bp), PACK(csize - asize, ));
insert_list(bp);
} else {
PUT(HDRP(bp), PACK(csize, ));
PUT(FTRP(bp), PACK(csize, ));
}
}
delete_list的实现如下
/*
* delete_list - 删除链表结点
*/
void delete_list(void *bp)
{
int index;
size_t size;
size = GET_SIZE(HDRP(bp));
index = getListOffset(size);
if (GET_PTR(bp) == NULL && GET_PTR((unsigned int *)bp + ) == NULL) {
/* 链表中唯一结点 */
PUT_PTR(heap_listp + WSIZE * index, NULL);
} else if (GET_PTR(bp) == NULL && GET_PTR((unsigned int *)bp + ) != NULL) {
/* 链表中最后一个结点, 不是唯一一个 */
PUT_PTR(GET_PTR((unsigned int *)bp + ), NULL);
} else if (GET_PTR(bp) != NULL && GET_PTR((unsigned int *)bp + ) == NULL){
/* 链表中第一个结点, 不是唯一一个 */
PUT_PTR(heap_listp + WSIZE * index, GET_PTR(bp));
PUT_PTR(GET_PTR(bp) + , NULL);
} else if (GET_PTR(bp) != NULL && GET_PTR((unsigned int *)bp + ) != NULL) {
/* 链表中的中间结点 */
PUT_PTR(GET_PTR((unsigned int *)bp + ), GET_PTR(bp));
PUT_PTR(GET_PTR(bp) + , GET_PTR((unsigned int*)bp + ));
}
}
这种方法很巧妙,不需要额外的空间维护freelist,需要的空间只是在初始化时创建的freelist头,其它指针只存在于空闲块中,并在malloc时删除。这个方法主要参考这里。
malloc的实现的更多相关文章
- malloc 与 free函数详解<转载>
malloc和free函数详解 本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...
- C 语言中 malloc、calloc、realloc 和free 函数的使用方法
C标准函数库中,常见的堆上内存管理函数有malloc(), calloc(), recalloc(), free(). 之所以使用堆,是因为栈只能用来保存临时变量.局部变量和函数参数.在函数返回时,自 ...
- 以冒泡排序为例--malloc/free 重定向stdin stdout
esort.c 代码如下,可关注下mallloc/free,freopen重定向的用法,排序为每轮将最小的数放在最前面: #include<stdio.h> #include<mal ...
- 内存动态分配之realloc(),malloc(),calloc()与new运算符
1,malloc与free是C/C++的标准库函数,new/delete是C++的运算符,是C++面向对象的特征,它们都可用于申请动态内存和释放内存.2,对于非内部数据类型的对象而言,光用maloc/ ...
- 在dll里malloc/new/cvCreate分配内存,在exe里free/Releases释放内存时会出错。
写了个程序,在DLL中用malloc分配了一块内存,但是在exe程序中释放,结果程序crash,原因就是:其原因可能是堆被损坏,这也说明 TestMySticker.exe 中或它所加载的任何 DLL ...
- Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解
C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般 ...
- malloc与new的区别
1.new是运算符,而malloc是库函数 2.new可以重载,可以自定义内存分配策略,甚至不做内存分配,甚至分配到非内存设备上.而malloc不能. 3.new在用于定义一个新的非内部对象的时候,默 ...
- new 等于 malloc加构造函数
1.new 是c++中的操作符,malloc是c 中的一个函数 2.new 不止是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数,而malloc则只分配内存,不会进行初始化类成员 ...
- 关于malloc函数的动态分配问题
malloc函数动态分配了一个整型的内存空间,让abc都指向刚申请的空间,所以只有最后一个赋值语句的值保留在了空间里 #include<stdio.h> main() { int *a,* ...
- 转:如何实现一个malloc
如何实现一个malloc 转载后排版效果很差,看原文! 任何一个用过或学过C的人对malloc都不会陌生.大家都知道malloc可以分配一段连续的内存空间,并且在不再使用时可以通过free释放掉. ...
随机推荐
- windows phone 扫描二维码
在网上找了找扫描二维码的例子,利用ZXing库实现(下载),提供的Silverlight版本的下载,在网上搜了一下已经有wp的dll可用了,不过网上实现的条码扫描的例子还都是用的Silverlight ...
- 【实习记】2014-08-29算法学习Boyer-Moore和最长公共子串(LCS)
昨天的问题方案一:寻找hash函数,可行性极低.方案二:载入内存,维护成一个守护进程的服务.难度比较大.方案三:使用前5位来索引,由前3位增至前5位唯一性,理论上是分拆记录扩大100倍,但可以 ...
- Kali linux网络配置
Kali linux 安装完成后,需要对其网络进行配置.使用DHCP服务是配置网卡最简单的方法之一,但渗透测试时通常不会这样做,因为系统会被记录在DHCP服务器的数据库中. 1 动态DHCP方式 配 ...
- demo_06Canvas
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- PL/SQL学习(五)异常处理
原文参考:http://plsql-tutorial.com/ 组成: 1) 异常类型 2) 错误码 3) 错误信息 代码结构: DECLARE Declaration section BEGIN ...
- TDirectory.IsRelativePath是否相对路径
使用函数: System.IOUtils.TDirectory.IsRelativePath class function IsRelativePath(const Path: string): Bo ...
- 使用EF6.0出现:CS0029 无法将类型“System.Data.Entity.Core.Objects.ObjectContext”隐式转换为“System.Data.Objects.ObjectContext”错误
这是因为EF6.0重构了一些命名空间后,和VS原有的实体数据模型模板不一致了(ObjectContext context = ((IObjectContextAdapter)dataContext). ...
- 基础canvas应用-钟表绘制
首先,canvas语法基础薄弱的小伙伴请点这里,剩下的小伙伴们可以接着往下看了. 一个表,需要画什么出来呢:3条线(时分秒针),1个圆(表盘),以及60条短线/点(刻度). 嗯,没毛病. 那接下来让我 ...
- SQLMAP系列教程
1.SQLMAP安装及access注入: http://www.stronkin.com/en/CompHonorBig.asp?id=7 2.Mysql数据库注入 http://www.slib ...
- NetFlow网络流量监测技术的应用和设计(转载)
http://blog.chinaunix.net/uid-20466300-id-1672909.html http://www.cww.net.cn/news/html/2014/12/25/20 ...