(转)零零散散学算法之浅析内存管理的方式
来源:互联网 发布:动态qos 知乎 编辑:程序博客网 时间:2024/06/16 11:04
解析内存管理的方式
正文
说到内存分配,我们立刻就会想到malloc()、calloc()等申请内存的接口,说到内存分配的算法,我们会想到Buddy和Slab等分配算法。那么你有没有思考过,申请的内存是如何管理的呢?管理的方式都有哪些?这就是本文将要讨论的。
本文将介绍两种内存管理的方法:链表法和比特位法。
第零节 问题初始化
假设现有一坨大小为M的内存,我们将它分为N块,那么每块的大小就是BLOCK_SIZE = M/N,如下图所示:
![](http://img.my.csdn.net/uploads/201212/15/1355550977_3915.png)
第一节 链表法
所谓链表法内存管理,就是说将已经分好的一坨内存分成了许多连续的小块,然后将每个小块以链表的形式串起来。如下图:
![](http://img.my.csdn.net/uploads/201212/15/1355551055_4713.png)
从图中可看到,我们在每个小块中添加了名为link的链表节点,它表示为:
- struct list_head
- {
- struct list_head *next, *prev;
- };
struct list_head{ struct list_head *next, *prev;};附注:在内核中该链表为双向链表,不过在上图中为了简洁,我将其表示为单链表。
于是,我们就可以用一个名为head的头结点将这些小块串联起来了。当我们使用时,只需从链表上摘一个即可,用完之后就可还回。利用链表来管理内存的优点有以下两点:
1. 即用即拿,用完即还(方便快捷):就是说当我们需要在这坨申请好的内存中使用一个或者几个小块时,我们就可根据需要,从链表上摘下来一个或者几个,用完之后直接还回链表中即可。
2. 管理流与数据流的融合与分离(节省空间):当我们利用链表法管理内存时,我们只需知道每个块的link,这样我们就能利用link来管理每个块,我们说它们是融合的;当你要使用某个块时,将其从链表中摘下来,这个时候我们就用这个块来进行数据流操作,对于link我们并不关心,在这个角度上我们说它们是分离的。不论融合与分离,我们在操作时并没有用到额外的空间,而是在每个块的内部解决了管理流与数据流。
好了,这就是链表法内存管理。节末,我还是给出链表法的代码:
- /**
- * 链表法内存管理:内存初始化
- * addr: 表示块的起始地址
- * block_size: 表示每个块的大小
- * block_number: 表示块的个数
- */
- void MemoryInit(void* addr, unsigned long block_size, unsigned int block_number)
- {
- int i = 0;
- struct list_head *link = (struct list_head*)addr;
- for(; i < block_number; i++)
- {
- list_add_tail(link, head);//添加到链表尾部
- addr += block_size;
- link = (struct list_head*)addr;
- }
- }
/** * 链表法内存管理:内存初始化 * addr: 表示块的起始地址 * block_size: 表示每个块的大小 * block_number: 表示块的个数 */void MemoryInit(void* addr, unsigned long block_size, unsigned int block_number){ inti = 0; struct list_head *link = (struct list_head*)addr; for(; i < block_number; i++) { list_add_tail(link, head);//添加到链表尾部 addr += block_size; link = (struct list_head*)addr; }}
- /**
- * 链表法内存管理:内存块分配
- */
- void* alloc_blkmem(void)
- {
- struct list_head *link = NULL;
- if(!list_empty(head))//链表不为空
- {
- link = head->next;
- list_del_init(link);//从链表中摘除
- }
- return link;
- }
/** * 链表法内存管理:内存块分配 */void* alloc_blkmem(void){ struct list_head *link = NULL; if(!list_empty(head))//链表不为空 { link = head->next; list_del_init(link);//从链表中摘除 } return link;}
- /**
- * 链表法内存管理:内存块释放
- *
- * addr: 表示块的起始地址
- */
- void free_blkmem(void* addr)
- {
- struct list_head *link = (struct list_head*)addr;
- list_add_tail(link, head);//还回到链表中
- }
/** * 链表法内存管理:内存块释放 * * addr: 表示块的起始地址 */void free_blkmem(void* addr){ struct list_head *link = (struct list_head*)addr; list_add_tail(link, head);//还回到链表中}
第二节 比特位法
和链表法相比,比特位法就更简单了。比特位的思想很简单,就是说当某个块没有被使用时,我们让该块对应位置的bit位为0,当这个块被使用时,就将它的bit位置为1。如下图:
![](http://img.my.csdn.net/uploads/201212/15/1355551586_5254.png)
比特位法的确很直观,这是它的优点,但是和链表法相比,它在时间和空间上都不及链表法。我们来看看:
在时间上:链表法是即用即拿,而比特位法则不然,它必须对bit表进行遍历,当bit位为0时方可取用;
在空间上:链表法不需额外的空间,而比特位法则取额外的空间来存储bitmap表,有一个块就得对应一个bit位,当数据块很多时,这也是一笔不消的开销。
虽然比特位法在时间上和空间上都不是很理想,但是它很直观,易理解。它也很常用!
好了,比特位法就是个这,因为它很直观,所以我用很简单的几句话就说完了。节末,还是老办法,给出比特位法的代码,纵然它很简单!
- /** 设置bitmap的指定位
- *
- * src: 表示bitmap
- * index:表示指定位
- */
- void bitmap_set_bit(void *src, unsigned int index)
- {
- unsigned short* data_bitmap = (unsigned short *)src;
- data_bitmap[index] |= 1 << index;
- }
/** 设置bitmap的指定位 * * src: 表示bitmap * index:表示指定位 */void bitmap_set_bit(void *src, unsigned int index){ unsigned short* data_bitmap = (unsigned short *)src; data_bitmap[index] |= 1 << index;}
- /** 清除bitmap的指定位
- *
- * src: 表示bitmap
- * index:表示指定位
- */
- void bitmap_clear_bit(void *src, unsigned int index)
- {
- unsigned short* data_bitmap = (unsigned short *)src;
- data_bitmap[index] &= ~(1 << index);
- }
/** 清除bitmap的指定位 * * src: 表示bitmap * index:表示指定位 */void bitmap_clear_bit(void *src, unsigned int index){ unsigned short* data_bitmap = (unsigned short *)src; data_bitmap[index] &= ~(1 << index);}
第三节 结束语
想想、写写、画画......
- 顶
- 13
- 踩
- 0
查看评论
- 5楼 h825503721昨天 15:24发表 [回复] [引用][举报]
- 零零散散学算法之浅析内存管理的方式
- (转)零零散散学算法之浅析内存管理的方式
- 零零散散学算法之判断集合的相同&相似性
- 零零散散学算法之详解几种最短路径
- 零零散散学算法之详解RMQ & LCA
- 零零散散学算法之详解RMQ & LCA
- 零零散散学算法之详解数据压缩算法(上)
- 零零散散学算法之详解数据压缩算法(下)
- 零零散散学算法之详解数据压缩算法(上)
- 零零散散学算法之详解数据压缩算法(下)
- 零零散散学算法之找出数组中重复的数---总结篇
- 零零散散学算法之详解几种数据存储结构
- 零零散散学算法之详解几种数据存储结构
- 零零散散学算法之详解最小生成树
- 零零散散学算法之详解二叉查找树
- 零零散散学算法之详解二叉查找树
- 零零散散学算法系列之目录(持续更新)
- 零零散散学算法之再叙字符串匹配
- AVR单片机模数转换的ADC实验 ATmega16
- JavaSE第五十讲:使用集合实现上一讲的作业
- 获取activity栈的最顶端的一个
- 云计算:大数据时代的系统工程(三)
- mysql主从热备
- (转)零零散散学算法之浅析内存管理的方式
- 微软Expression真的迎来了末日
- 【每日一练】(第2期)关于静态成员的理解
- Tab的用法
- iOS delegate 实现页面之间的传值
- UltraEdit中使用正则表达式替换
- 将时间统一转化成为yyyy-MM-dd格式
- mongodb启动出现 无法定位程序输入点 InterlockedCompareExchange64
- 视频编码的守望者--Jason Garrett-Glaser