数据结构随笔—动态存储管理

来源:互联网 发布:淘宝客导购名称怎么填 编辑:程序博客网 时间:2024/05/17 06:26

动态存储管理的基本问题是如何应用户请求分配内存,如何回收那些用户不在使用而释放的内存。

经过一段时间的运行,有些用户运行结束,它所占用的内存区变成空闲块,只就使整个内存区呈现出占用快和空闲块交错的状态,假如此时又有新的用户进入系统请求分配内存,这时通常有两种做法:

(1)、继续从高地址的空闲块中进行分配,直到分配无法进行,系统才去回收所有用户不再使用的空闲块,并且重新组织内存,将所有空闲的内存块连接在一起成为一个大的空闲块。

(2)、用户一旦运行结束,便将它所占用的内存块释放成空闲块。当有新用户请求分配内存时,系统巡视整个内存区中所有的内存块,并从中找出一个合适的空闲块分配。

可利用空间表及分配方法

可利用空间表有下列3种不同的结构形式:

(1)、系统运行期间所有用户请求分配的存储量的大小相同;每个内存块的大小相同。

(2)、系统运行期间用户请求分配的存储量有若干种大小的规格;建立若干个可利用空间表,同一链表中的结点大小相同。并增加一个标志位tag,表示是空闲还是占用。当请求的内存块过大时,执行存储紧缩操作。

(3)、系统在运行期间分配给用户的内存块大小不固定,可以随请求而变化。所以可利用的空间表只有一个大小为整个内存区的结点。

分配策略:

(1)首次拟合法:从表头指针开始查找可利用空间表,将找到的第一个大小不小于n的空闲块的一部分分配给用户。

(2)最佳拟合法:将可利用空间表中一个不小于n且最接近n的空闲块的一部分分配给用户。所以可利用空间表应该从小到大排序

(3)最差拟合法:将可利用空间表中不小于n且是链表中最大的空闲块的一部分分配给用户。所以可利用空间表可以从大到小排序。

边界标识法:

在每个内存区的头部和底部两个边界上分别设有标识,以标识给区域为占用快或者空闲块,以便将所有地址连续的空闲存储区组成一个尽可能大的空闲块。

头部有4个区域:llink指向前驱结点,tag标识空闲或者占用,size表示大小,rlink指向后驱结点。

尾部有2个区域:uplink底部阈,本节点的低指针。tag标识空闲或者占用。

分配算法:

假设首次拟合法,边界标识法还有如下两条约定:

1、首次拟合会出现有很多容量极小总也分配不出去的空闲块,这就大大减慢了分配的速度(查找)的。弥补的办法是:选定一个适当的常量e,当容量m-请求量n<e时,就将容量m的空闲块整块分配给用户。

2、如果每次分配都是从同一个结点开始查找,会造成存储量小的结点密集在头指针附近这同样会增加查询较大空闲块的时间。所以避免的方法是在每次分配之后,令指针pav指向刚进行过分配的结点的后继结点。

回收算法

1、如果释放块的左右邻区都是占用块。此时简单插入即可。

2、如果释放块的作用邻区有一个是空闲块。

3、左右邻区都是空闲块。

伙伴系统

在伙伴系统中,无论是占用块或空闲块,其大小均是2的k次幂。

分配算法

在可利用表上寻找结点大小与n相匹配的子表,若非空,则直接分配,若空,则到更大的非空子表中去查找,知道找到一个空闲块,将剩余部分插入到相应的子表。

回收算法

伙伴:在分配时经常需要将一个大的空闲块分裂成两个大小相等的存储区,这两个由同一大块分裂出来的小块就称之为互为伙伴。

在回收空闲块时,应首先判别其伙伴是否为空闲块,若否,则只要将释放的空闲块插入到相应的子表即可。若是,则需要在相应子表中找到其伙伴并删除之,然后在判别合并后的伙伴是否是空闲块。以此重复,知道归并到所得空闲块的伙伴不是空闲块时,在插入到相应的子表中去。

无用单元收集

无用单元和悬挂访问:解决途径:

(1)使用访问计数器:在子表或者广义表中增加一个表头结点。他的值是指向该子表或者广义表的指针数目;当为零时,释放结点‘

(2)当可用表为空是才回收,将不被使用的结点链接在一起,成为一个新的可利用空间表,而后程序在继续运行。

存储紧缩:在堆的动态存储管理方法中,可利用空间不管什么时候都是一个连续的存储区。从低到高依次分配。当回收空闲块合并到堆上去的时候称为存储紧缩。

有两种方式:

(1)一旦有用户释放存储块即进行回收紧缩。

(2)在程序执行过程中不回收,直到可利用空间不够的时候或者堆指针指向最高地址时才进行存储紧缩。将所有空闲块练成一片即将占用块都集中到低地址区,而剩余的高地址区成为一个连续地址的空闲块。

还需要以下4步:

1、计算占用块的新地址。

2、修改用户的初始变量表。

3、检查每个占用块中存储的数据。

4、将所有占用块迁移到新地址去。


1 0