C语言动态内存管理
动态存储管理的基本问题是:系统如何按请求分配内存,如何回收内存再利用。提出请求的用户可能是系统的一个作业,也可能是程序中的一个变量。
空闲块
未曾分配的地址连续的内存区称为“空闲块”。
占用块
已分配给用户使用的地址连续的内存区称为“占用块”。
系统刚刚启动时,整个内存可看做一个大的“空闲块”,随着用户请求的进入,系统依次分配相应的内存。
在系统运行过程中,内存被分为两大部分:低地址区(若干占用块)和高地址区(空闲块)。
经过一段时间后,有的程序运行结束,释放掉它所占用的内存,使之变为空闲块,这就使整个内存中空闲块和占用块之间出现了相互交错的现象。如下图:
当系统进入到图中b),又有新的用户请求分配内存时,系统该如何处理呢?
方法一:系统继续从高地址区的空闲块进行分配,直到无法分配。当剩余的空闲块不能满足分配请求时,系统才去回收所有的不再使用的内存区,并重新组织内存,紧凑所有的空闲块为一个大的空闲块,以备在分配。
方法二:空闲链表。空闲链表中包含了所有空闲块的信息,一个节点对应一个空闲块。当用户请求分配时,系统所作的工作就是搜索空闲链表,按某种策略找到一个合适的空闲块进行分配,并删除对应的节点。当用户释放所占用的内存时,系统回收该内存,并将它插入到空闲链表中。
空闲链表三种结构形式:
(1)所有请求的内存大小相同。这是一种最简单的动态存储管理方式。
对此,系统通常的做法是:
a)系统启动时,将内存按大小均分成若干个块,并形成一个链表。
b)分配时,只需将链表中第一个节点分配给用户即可,无需扫描整个链表。
c)回收时,将空闲块插入到链表头即可。
(2)所有请求的内存大小有n种规格。可创建n个(1)情况中的链表,分配与回收与(1)类似,不同之处在于:当请求的链表为空时,需要在节点大的链表上进行分配,取一部分内存给用户,剩余部分作为一个新节点插入到相应的链表中。
(3)所有请求的内存大小是不同的,是不断发生变化的。这种情况下的分配与回收见下篇。
对于内存块大小不同的空闲链表,假如有一个大小为N的内存申请,如果空闲链表中大于N的内存只有一块,假如大小为M,就把M的一部分分配给用户,同时把剩余的M-N的部分作为一个节点插入到空闲链表中。
当大于N的内存有多块时,我们该如何分配呢?通常有以下三种方法:
(1)最先适配法。顾名思义,顺序扫描空闲链表,找到第一个大于等于N的空闲块,把其中的N分配给用户。因为链表不按内存的地址有序,也不按大小有序,所以回收内存块放到表头即可。
问题:运行一段时间后,链表中将会出现一些非常小的块,并在这些小块都在链表的前边。
(2)最优适配法。在空闲链表中找到一个不小于N并且最接近N的空闲块分配给用户。分配时需要整表扫描。如果链表按空闲块从小到大有序,分配时只需找到第一个大于N的空闲块,回收时需要插入到链表合适的位置上。
(3)最差适配法。将链表中不小于N且是链表中最大的空闲块的一部分分配给用户。链表可按空闲块从大到小的顺序排列,分配只需判断链表第一个空闲块即可,回收时需要插入到链表合适的位置上。
对于回收,我们考虑的不仅仅是归还节点,还要考虑空闲块的合并问题。这种把物理地址相邻的空闲块的合并以取得更大的空闲块的方法是需要的。空闲链表中的空闲块并不是按物理地址有序的,那又如何快速合并呢?下篇中将讨论一种方法:边界标识法
原文链接:http://blog.csdn.net/hbuxiaoshe/article/details/5994743
就空闲链表来说,要确定哪些空闲块是物理地址相邻的,确实不太容易,需要整表扫描。
边界标识法能够有效的判断空闲块的物理相邻内存块是否为空闲块。
所有的空闲块组成一个双向循环链表,链表中每一个节点的结构如下:
llink和rlink分别指向链表中的前驱后继节点。
size表明内存块的大小。
uplink指向本块的首地址,图中箭头,其作用下面讲述。
tag头和尾中各有一个,作为内存块边界的标识,0表空闲块,1表占用块。
分配时同样会在链表上产生很多非常小的空闲块,影响分配的效率,因此,可以定义一个全局的指针p,当不为空时分配,使其始终指向刚进行过分配的节点的后继节点。
回收时判断物理相邻的块是否为空闲块的方法:
假设当前回收块的物理地址为p(下面涉及到的左邻块和右邻块都是物理地址相邻的,在循环链表中也许不相邻),
左邻块:左邻块的尾的地址是p1=p-sizeof(尾),左邻块是否为空闲块的判断则为p1->tag是否为0。当为空闲块时,只需将当前块合并到左邻块中即可,而左邻块的地址则需要由uplink来获得(原因是中间内存块的大小是不固定的,不能通过偏移来实现),即p1->uplink。修改左邻块的size和uplink即可。
右邻块:右邻块的首的地址为p2=p+sizeof(头),右邻块是否为空闲块的判断则为p2->tag是否为0。当为空闲块时,与右邻块合并,修改p的llink、rlink和size,修改p2的uplink。
你可能会认为,既然链表中的块都是空闲块,干吗还要加上tag标识位呢?我的回答是,如果没有tag,当我们找到右邻块的地址时,没有办法判断右邻块是不是链表中的一个节点,也许它还在被用户使用着。那为什么要用两个tag呢?个人觉得,用一个也可以,但用两个更容易判断。
C语言动态内存管理的更多相关文章
- C++中对C的扩展学习新增语法——动态内存管理
1.C语言动态内存管理的缺点: 1.malloc对象的大小需要自己计算. 2.需要手动转换指针类型. 3.C++的对象不适合使用malloc和free. 2.C++中new/delete基本使用: 3 ...
- C语言之动态内存管理
C语言之动态内存管理 大纲: 储存器原理 为什么存在动态内存的开辟 malloc() free() calloc() realloc() 常见错误 例题 柔性数组 零(上).存储器原理 之前我们提到了 ...
- JVM内存管理------JAVA语言的内存管理概述
引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...
- C语言的内存管理
C语言的内存管理 转载:http://blog.csdn.net/wind19/article/details/5964090 对于一个C语言程序而言,内存空间主要由五个部分组成代码段(.text ...
- FreeRTOS 动态内存管理
以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 动态内存管理,动态内存管理是 FreeRTOS 非常重要的一项功能,前面 ...
- JVM内存管理之JAVA语言的内存管理概述
引言 内存管理一直是JAVA语言自豪与骄傲的资本,它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节,只专注于业务逻辑.不过世界上不存在十全十美的好事,在带来了便利的同时,也因此引入了很多令人抓 ...
- 动态内存管理详解:malloc/free/new/delete/brk/mmap
c++ 内存获取和释放 new/delete,new[]/delete[] c 内存获取和释放 malloc/free, calloc/realloc 上述8个函数/操作符是c/c++语言里常用来做动 ...
- 字符串输出输入函数,const修饰符,内存分区,动态内存管理,指针和函数,结构体
1.字符串输出输入函数 读入字符串的方法: 1) scanf 特点:不能接收空格 2) gets 特点:可以接受含有空格的字符串 ,不安全 3) fgets(); 特点:可以帮我们自动根据数组的长度截 ...
- 动态内存管理---new&delete
动态内存管理 动态对象(堆对象)是程序在执行过程中在动态内存中用new运算符创建的对象. 因为是用户自己用new运算符创建的.因此也要求用户自己用delete运算符释放,即用户必须自己管理动态内存. ...
随机推荐
- HW—指定字符替换Java(replace)---动态和静态定义字符串数组;
总结: 语法层面上:这里主要用到Java字符串的替换函数,str.replaceAll("待替换的","替换成的").replaceAll接受的是正则花的reg ...
- 第十六篇、MBprogressHUD的使用和获取当前的控制器
简介: 在开发应用的时候,为了更好的增加用户的体验,常常在客户端向服务端请求数据的时候,在适当的地方加上非模态HUD,让用户可以可以知道当前的进度,稍作等待. MBProgressHUD 第三方框架G ...
- 使用SQL Server 2005 新的语法ROW_NUMBER()进行分页的两种不同方式的性能比较
相比在SQL Server 2000 中使用的分页方式,在SQL Server 2005中使用新的语法ROW_NUMBER()来分页效率要高出很多,但是很多人在使用ROW_NUMBER()这种分页方式 ...
- 计算 unique word numbers
计算不重复单词的个数 参考: 1.Unique words count
- Trie的C++实现及HDU1251,hdu1671
#include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...
- libjingle线程机制
libjingle包装了所有的线程,包括signaling thread,worker thread, 和其它任何线程,用talk_base::Thread来包装.所有的 Thread对象由Threa ...
- Eclipse代码自动提示
发现了一个好用的快捷键,不用跳转到源文件就可以看源代码:先按shift键,然后鼠标点击要看的代码,即可.
- echshop 微信扫码支付 遇到的问题
参考的网站 (转)http://www.ecshop119.com/ecshopjc-937.html(转)http://www.6gdown.com/softedupage/58929.html ...
- 谈谈我对OAuth的理解
自己的理解是,OAuth是一种授权标准. 用于为除了用户之外的第三方应用授权, 并且在授权过程中,第三方应用不会接触到用户的任何信息, 授权完成后,第三方应用可访问用户授权范围内的信息. ...
- (用微信扫的静态链接二维码)微信native支付模式官方提供的demo文件中的几个bug修正
native支付模式一demo(用微信扫的静态链接二维码)BUG修复,一共4个BUG 1.native_call_qrcode.php这个文件中的代码无法生存native支付的短地址2.WxPayPu ...