36
数数数数 数数 中中中中中中中中中中中中 中中中中中中中中中中中中 数数数数 数数数数 数数数 数数数 数数数数数数 数数数数数数

数据结构 第八章动态存储管理

  • Upload
    cassie

  • View
    134

  • Download
    0

Embed Size (px)

DESCRIPTION

数据结构 第八章动态存储管理. 本章内容 8.1 动态存储管理概述 8.2 可利用空间表及分配方法 8.3 边界标识法 8.4 伙伴系统. 8.1 动态存储管理概述. 存储管理 —— 每一种数据结构都必须研究该结构的存储结构,但它是借助于某一高级语言中的变量说明来加以描述的,并没有涉及到具体的存储分配。 实际上,结构中的每个数据元素都占有一定的内存位置,在程序执行的过程中,数据元素的存取是通过对应的存储单元来进行的。 研究 数据存储 与 内存单元 对应问题,就是存储管理问题。. 8.1 动态存储管理概述. 动态存储管理的基本问题 - PowerPoint PPT Presentation

Citation preview

Page 1: 数据结构 第八章动态存储管理

《 数据结构》课程

中国科学技术大学网络学院中国科学技术大学网络学院

数据结构数据结构第八章第八章 动态存储管理动态存储管理

Page 2: 数据结构 第八章动态存储管理

本章内容

8.1  动态存储管理概述8.2 可利用空间表及分配方法8.3 边界标识法8.4 伙伴系统

Page 3: 数据结构 第八章动态存储管理

8-3 中国科大《数据结构》

8.1 动态存储管理概述

存储管理存储管理——每一种数据结构都必须研究该结构的存储结构,但它——每一种数据结构都必须研究该结构的存储结构,但它是借助于某一高级语言中的变量说明来加以描述的,并没有涉及到是借助于某一高级语言中的变量说明来加以描述的,并没有涉及到具体的存储分配。具体的存储分配。

实际上,结构中的每个数据元素都占有一定的内存位置,实际上,结构中的每个数据元素都占有一定的内存位置,在程序执行的过程中,数据元素的存取是通过对应的存储单元来进在程序执行的过程中,数据元素的存取是通过对应的存储单元来进行的。行的。

研究研究数据存储数据存储与与内存单元内存单元对应问题,就是存储管理问题。对应问题,就是存储管理问题。

Page 4: 数据结构 第八章动态存储管理

8-4 中国科大《数据结构》

8.1 动态存储管理概述

动态存储管理的基本问题动态存储管理的基本问题1.1. 如何根据用户提出的“请求”来分配内存。如何根据用户提出的“请求”来分配内存。2.2. 如何收回被用户“释放”的内存,以备新的“请求”产生时重如何收回被用户“释放”的内存,以备新的“请求”产生时重

新进行分配。新进行分配。

Page 5: 数据结构 第八章动态存储管理

8-5 中国科大《数据结构》

8.1 动态存储管理概述

存储原理存储原理 计算机内存在刚工作时,空闲部分是一个整块的连续区域;计算机内存在刚工作时,空闲部分是一个整块的连续区域; 不断运行程序,多次申请和释放内存以后,空闲内存不再连续,不断运行程序,多次申请和释放内存以后,空闲内存不再连续,

形成多个不连续的空闲区。形成多个不连续的空闲区。 动态存储管理:指系统随机地根据用户程序申请空间的大小,动态存储管理:指系统随机地根据用户程序申请空间的大小,

进行分配空间和回收不用空间所进行的内存管理。进行分配空间和回收不用空间所进行的内存管理。 占用块占用块:将系统已分配给用户使用的地址连续的内存区域为:将系统已分配给用户使用的地址连续的内存区域为

“占用块”;“占用块”; 空闲块空闲块:称未曾分配的地址连续的内存区为“空闲块”。:称未曾分配的地址连续的内存区为“空闲块”。

内存的初始状态

U2 U4

系统运行若干时后

U1 U2 U3 U4

系统运行初期

Page 6: 数据结构 第八章动态存储管理

8-6 中国科大《数据结构》

8.1 动态存储管理概述 可利用空间表可利用空间表

内存空间的所有可利用的空闲空间的情况记录表。有两种结构:内存空间的所有可利用的空闲空间的情况记录表。有两种结构:1.1. 目录表;目录表;2.2. 链表:一个结点表示一个空闲块。链表:一个结点表示一个空闲块。

av

150001500000

100008000800000

31000^̂410004100000

59000

链表

目录表

空闲空闲41000410005900059000

空闲空闲800080003100031000

空闲空闲15000150001000010000

内存状态0 10000

25000

31000

39000

59000 99999

Page 7: 数据结构 第八章动态存储管理

8-7 中国科大《数据结构》

8.2 可利用空间表及分配方法

本节主要讨论利用可利用空间表进行动态存储分配的方法。本节主要讨论利用可利用空间表进行动态存储分配的方法。目录表法比较简单,在《操作系统》课程中已详细介绍。本节仅讨目录表法比较简单,在《操作系统》课程中已详细介绍。本节仅讨论链表方法分配内存。论链表方法分配内存。

Page 8: 数据结构 第八章动态存储管理

8-8 中国科大《数据结构》

8.2 可利用空间表及分配方法

三种结构形式:三种结构形式: 第一种情况第一种情况:系统运行期间所有用户请求分配的存储量大小相:系统运行期间所有用户请求分配的存储量大小相

同;同;具体作法是具体作法是:开始运行时将内存区分割成若干大小相同的:开始运行时将内存区分割成若干大小相同的块,形成一可利用链表,分配和回收操作如同一般链表。块,形成一可利用链表,分配和回收操作如同一般链表。

第二种情况第二种情况:系统运行期间用户请求分配的存储量有若干种大:系统运行期间用户请求分配的存储量有若干种大小的规格;小的规格;具体作法是具体作法是:先建立若干个可利用空间表,同一链:先建立若干个可利用空间表,同一链表中的结点小相同,分配表中的结点小相同,分配 // 回收情况:回收情况: 结点大小与请求分配量相同时;结点大小与请求分配量相同时; 结点大小比请求量大时;结点大小比请求量大时; 结点大小比请求量小时。结点大小比请求量小时。

Page 9: 数据结构 第八章动态存储管理

8-9 中国科大《数据结构》

8.2 可利用空间表及分配方法

节点结构节点结构

tagtag typetype linklink

ValueValue

type = 0 节点大小为 2 字节1 节点大小为 4 字节2 节点大小为 8 字节

tag = 0 空闲块1 占用块

0000 0000 0000…av2

1100 1100 1100…av4

0000 0000 0000…av8

可利用空间表

Page 10: 数据结构 第八章动态存储管理

8-10 中国科大《数据结构》

8.2 可利用空间表及分配方法

第三种情况:系统在运行期间分配给用户的内存块的大小不固定,可以随请求而变。

工作情况:系统刚开始工作时,整个内存空间是一个空闲块,随时着分配和回收的进行,可利用空间表中的结点大小和个数也随之而变。

Page 11: 数据结构 第八章动态存储管理

8-11 中国科大《数据结构》

8.2 可利用空间表及分配方法

分配方法分配方法 若某用户需大小为若某用户需大小为 nn 的内存,而可利用空间仅有一块大小为 的内存,而可利用空间仅有一块大小为

m≥n m≥n 的空闲块,则只需将其中大小为的空闲块,则只需将其中大小为 n n 的一部分分配给申请的一部分分配给申请的用户,同时将乘余的 的用户,同时将乘余的 m-n m-n 的部分作为一个结点留在链表中的部分作为一个结点留在链表中即可。即可。

若可利用空间表有若干个不小于若可利用空间表有若干个不小于 nn 的空闲块时,可有三种不同的空闲块时,可有三种不同的分配方案:的分配方案:

Page 12: 数据结构 第八章动态存储管理

8-12 中国科大《数据结构》

8.2 可利用空间表及分配方法

1.1. 首次拟合法首次拟合法 分配找到的第一个不小于分配找到的第一个不小于 nn 的空闲块的一部分。的空闲块的一部分。 操作方便,查找快捷;操作方便,查找快捷;

2.2. 最佳拟合法最佳拟合法 分配不小于分配不小于 nn 且最接近且最接近 nn 的空闲块的一部分。的空闲块的一部分。 尽可能将大的空闲块留给大程序使用;尽可能将大的空闲块留给大程序使用;

3.3. 最坏拟合法最坏拟合法 分配不小于分配不小于 nn 且是最大的空闲块的一部分。且是最大的空闲块的一部分。 尽可能减少分配后无用碎片;尽可能减少分配后无用碎片;

Page 13: 数据结构 第八章动态存储管理

8-13 中国科大《数据结构》

8.2 可利用空间表及分配方法

内存的分配与回收内存的分配与回收 分配分配

根据申请内存大小利用相应分配策略分配给用户所需空间;根据申请内存大小利用相应分配策略分配给用户所需空间;若分配块大小与申请大小相差不多,则将此块全部分给用户;若分配块大小与申请大小相差不多,则将此块全部分给用户;否则,将分配块分为两部分,一部分给用户使用,另一部分否则,将分配块分为两部分,一部分给用户使用,另一部分继续留在可利用空间表中。继续留在可利用空间表中。

回收回收测试回收块前后相邻内存块是否空闲;测试回收块前后相邻内存块是否空闲;若是则需将回收块与相邻空闲块合并成较大的空闲块,再链若是则需将回收块与相邻空闲块合并成较大的空闲块,再链入可利用空间表中。入可利用空间表中。

Page 14: 数据结构 第八章动态存储管理

8-14 中国科大《数据结构》

8.3 边界标识法 用以进行动态分区分配的一种管理方法用以进行动态分区分配的一种管理方法 节点结构节点结构

headhead llinkllink tagtag sizesize rlinkrlink

spacespace

footfoot uplinkuplink tagtag

可利用空间表中的节点结构图

可利用空间表中的节点结构定义

type struct WORD { //WORD, 内存数据类型 union { //head 和 foot 分别是节点的第一个和最后一个字 WORD *llink; //头部域,指向前趋节点 WORD *rlink; //底部域,指向本节点头部 };

int tag; // 块标志 : 0 空闲 ,1 占用 .头部和尾部均有 int size; //头部域,块大小 WORD *rlink; //头部域,指向后继节点 otherType other; // 字的其他部分} WORD, head, foot, *Space; //*Space: 可利用空间指针类型

#define FootLoc(p) p+p->size-1 // 指向 p 所指节点的底部

Page 15: 数据结构 第八章动态存储管理

8-15 中国科大《数据结构》

8.3 边界标识法

分配算法:分配算法:采取首次拟合法进行分配。有两个约定:采取首次拟合法进行分配。有两个约定:1.1. 假设待分配的内存空闲块容量为假设待分配的内存空闲块容量为 m m 个字,若每次分配只从中个字,若每次分配只从中

分配分配 nn 个字个字 (n<m)(n<m) 给用户,剩余给用户,剩余 m-nm-n 个字的节点仍留在表中,个字的节点仍留在表中,若干次分配后,链表中存在大量容量极小,总分配不出去的空若干次分配后,链表中存在大量容量极小,总分配不出去的空闲块。解决的办法是:确定一个常量闲块。解决的办法是:确定一个常量 ee ,当,当 m-n<em-n<e 时,就将时,就将容量为容量为 mm 的空闲块整块分配给用户,否则只分配其中的空闲块整块分配给用户,否则只分配其中 nn 个字个字的块,同时为了避免修改指针,约定将该节点中的高地址部分的块,同时为了避免修改指针,约定将该节点中的高地址部分分配给用户。分配给用户。

2.2. 若每次分配都从同一节点开始查找,会使存储量小的节点密集若每次分配都从同一节点开始查找,会使存储量小的节点密集在头指针在头指针 pavpav 所指节点附近,这会增大寻找到较大空间块的时所指节点附近,这会增大寻找到较大空间块的时间。避免的方法是,每次从不同的节点开始查找,使剩余小块间。避免的方法是,每次从不同的节点开始查找,使剩余小块均匀地分布在链表中。实现方法是,每次分配后,令指针均匀地分布在链表中。实现方法是,每次分配后,令指针 pavpav

指向刚进行过分配的节点的后继节点。指向刚进行过分配的节点的后继节点。

Page 16: 数据结构 第八章动态存储管理

8-16 中国科大《数据结构》

8.3 边界标识法

分配算法 分配算法 (( 见教材第见教材第 200200 页页 ))

Space AlloctionBoundTag(Space &pav, int n) { // 若有不小于 n 的空闲块,则分配之, // 并返回首地址;否则返回 NULL.

// 若分配后可利用的空间表不空, // 则 pav 指向表中刚分配过的节点后继节点 for (p=pav; p&&p->size<n && p->rlink!=pav; p=p->rlink;) // 如果查找不小于 n 的空闲块,找不到返回 NULL

if (!p || p->size<n) pav = NULL;

else //p 指向找到的空闲块 { f=FootLoc(p); // 指向底部 pav=p->rlink; //pav 指向 *p 节点的后继 if (p->size-n<=e) // 整块分配,不保留 <e 的剩余量 { if (pav==p) pav=NULL;// 可利用空间表为空 else // 在表中删除分配的节点

{ pav->llink=p->llink;p->llink->rlink =pav; }

p->tg=f->tag=1; //修改分配节点的头部和底部标志

}

else // 分配该块后的 n 个字

{ f->tag=1; //修改分配块的底部标志 p->size - =n; //修改剩余块大小 f=FootLoc(p); // 指向剩余块底部

f->tag=0;

f->uplink=p; //设置剩余块底部 p=f+1; // 指向分配块头部 p->tag=1;

p->size=n; //设置分配块头部

}

return p; //返回分配块的首地址

}

}

Page 17: 数据结构 第八章动态存储管理

8-17 中国科大《数据结构》

8.3 边界标识法

回收算法回收算法用户释放占用块后,系统需立即回收以备新的请求产生时用户释放占用块后,系统需立即回收以备新的请求产生时

进行再分配。为了使物理地址毗邻的空闲块结合成一个尽可能大的进行再分配。为了使物理地址毗邻的空闲块结合成一个尽可能大的结点,则首先需要检查刚释放的占用块的左、右紧邻是否为空闲块。结点,则首先需要检查刚释放的占用块的左、右紧邻是否为空闲块。

假设用户释放的内存区的头部地址为假设用户释放的内存区的头部地址为 pp ,则,则p-1=p-1= 与其低地址紧邻的内存区的底部地址,即左邻区;与其低地址紧邻的内存区的底部地址,即左邻区;p+pp+p -- >size=>size= 与其高地址紧邻的内存区的头部地址与其高地址紧邻的内存区的头部地址 ,,即右邻即右邻

区。区。

Page 18: 数据结构 第八章动态存储管理

8-18 中国科大《数据结构》

8.3 边界标识法

a)a) 释放块的左、右邻区均为占用块释放块的左、右邻区均为占用块此时只要作简单插入即可。由于边界标识法在按首次拟合此时只要作简单插入即可。由于边界标识法在按首次拟合

进行分配时对可利用空间表的结构没有任何要求,则新的空闲块插进行分配时对可利用空间表的结构没有任何要求,则新的空闲块插入在表中任何位置均可。简单的做法就是插入在入在表中任何位置均可。简单的做法就是插入在 pavpav 指针所指结点指针所指结点之前(之后),描述如下:之前(之后),描述如下:

p- >tag = 1= 0;FootLoc (p)- >uplink = p;FootLoc (p)- >tag = 0;if (!pav)

pav = p- >llink = p- >rlink = p;else { q = pav- >llink;

p- >rlink = pav;p- >llink = q;q- >rlink = pav- >llink = p;pav = p; //令刚释放的结点为下次分配时的最先查询的

结点}

Page 19: 数据结构 第八章动态存储管理

8-19 中国科大《数据结构》

8.3 边界标识法

b)b) 释放块的左邻区为空闲块,而右邻区为占用块释放块的左邻区为空闲块,而右邻区为占用块由于释放块的头部和左邻空闲块的底部毗邻,因此只要改由于释放块的头部和左邻空闲块的底部毗邻,因此只要改

变左邻空闲块的结点:增加结点的变左邻空闲块的结点:增加结点的 sizesize 域的值且重新设置结点的域的值且重新设置结点的底部即可。描述如下底部即可。描述如下

n = p- >size; // 释放块的大小s = (p- 1)- >uplink; //左邻空闲块的头部地址s- >size + = n; //设置新的空闲块大小f = p + n- 1; //设置新的空闲块底部f- >uplink = s;f- >tag = 0;

Page 20: 数据结构 第八章动态存储管理

8-20 中国科大《数据结构》

8.3 边界标识法

c)c) 释放块的右邻区为空闲块,而左邻区为占用块释放块的右邻区为空闲块,而左邻区为占用块由于释放块的底部和右邻区空闲块的头部毗邻,因此,当由于释放块的底部和右邻区空闲块的头部毗邻,因此,当

表中结点由原来的右邻空闲块变成合并后的大空闲块时,结点的底表中结点由原来的右邻空闲块变成合并后的大空闲块时,结点的底部位置不变部位置不变 ,, 但头部要变但头部要变 ,,由此由此 ,, 链表中的指针也要变。描述如下:链表中的指针也要变。描述如下:

t = p + p- >size; //右邻空闲块的头部地址p- >tag = 0; //p 为合并后的结点头部地址q = t- >llink; //q 为 *t 结点在可利用空间表中的前驱结点的头部地址p- >llink = q; //q 指向 *p 的前驱q- >rlink = p;q1 = t- >rlink; //q1 为 *t 结点在可利用空间表中的后继结点的头部地址p- >rlink = q1; //q1 指向 *p 的后继q1- >llink = p;p- >size + = t- >size; // 新的空闲块的大小FootLoc (t)- >uplink = p; //底部指针指向新结点的头部

Page 21: 数据结构 第八章动态存储管理

8-21 中国科大《数据结构》

8.3 边界标识法

d)d) 释放块的左、右邻区均为空闲块释放块的左、右邻区均为空闲块为使为使 33 个空闲块连接在一起成为一个大结点留在可利用空个空闲块连接在一起成为一个大结点留在可利用空

间表中,只要增加左邻空闲块的间表中,只要增加左邻空闲块的 spacespace 容量,同时在链表中删去容量,同时在链表中删去右邻空闲块结点即可。所作改变可描述如下:右邻空闲块结点即可。所作改变可描述如下:

n = p- >size; // 释放块的大小s = (p- 1)- >uplink; // 指向左邻块t = p + p- >size; // 指向右邻块s- >size + = n + t- >rlink; //设置新结点的大小q = t- >llink; //q != q1

q1 = t- >rlink;q- >rlink = q1; //删去右邻空闲块结点q1- >llink = q;FootLoc (t)- >uplink = s; // 新结点底部指针指向其头部

Page 22: 数据结构 第八章动态存储管理

8-22 中国科大《数据结构》

8.3 边界标识法

例如,在上述情况下可利用空间表的变化如图 8.6 所示。

30 000

1 20 000

1

20 000

0

0 30 000

左邻区

释放块

(a) 释放的存储块 (b) 左邻区是空闲块的情况

(c) 右邻区是空闲块的情况0

0 35 000 0 15 000

右邻区

释放块 右邻区

释放块

Page 23: 数据结构 第八章动态存储管理

8-23 中国科大《数据结构》

8.3 边界标识法

(d) 左、右邻区均是空闲块的情况

回收存储块后的可利用空间表

0

0 15 000 0 45 000

右邻区

释放块

右邻区左邻区

Page 24: 数据结构 第八章动态存储管理

8-24 中国科大《数据结构》

8.3 边界标识法

边界表示法的问题边界表示法的问题 查找适合需要的块,需要较多的时间查找适合需要的块,需要较多的时间 查找适合需要的块的策略(最先查找适合需要的块的策略(最先 // 最佳最佳 // 最坏),每种都有最坏),每种都有缺陷缺陷

碎片问题碎片问题

Page 25: 数据结构 第八章动态存储管理

8-25 中国科大《数据结构》

8.4 伙伴系统

伙伴系统伙伴系统 (buddy system)(buddy system) :是操作系统中用到的一种动态存储管:是操作系统中用到的一种动态存储管理方法。它和边界标识法类似,在用户提出申请时,分配一块大小理方法。它和边界标识法类似,在用户提出申请时,分配一块大小“恰当”的内存区给用户;反之,在用户释放内存区时即收回。“恰当”的内存区给用户;反之,在用户释放内存区时即收回。

伙伴系统的特点伙伴系统的特点:无论是占用块或空闲块,其大小均为:无论是占用块或空闲块,其大小均为 22 的的 kk 次幂次幂(( kk 为某个正整数)。为某个正整数)。

Page 26: 数据结构 第八章动态存储管理

8-26 中国科大《数据结构》

8.4 伙伴系统

结点结构

表头结点

head llink tag kval rlink

space

nodesize first

结点:右头部 head 和 space 域组成。 head :为结点头部,是一个由 4 个域组成的记录。 llink : 链域,指向同一链表中的前驱结点。 rlink : 链域,指向同一链表中的后继结点。 tag : 标志域,值为“ 0” 表示空闲块,值为“ 1” 表示占用块。 kval : 其值为 2 的幂次 k 。 space :数据域,是一个大小为 2k- 1 个字的连续内存空间。 表头结点:由两个域组成。 nodesize :表示该链表中空闲块的大小。 first :该链表的表头指针。

Page 27: 数据结构 第八章动态存储管理

8-27 中国科大《数据结构》

8.4 伙伴系统

可利用空间表的结构 C语言描述#define m 16 // 可利用空间总容量 64k 字的 2 的幂次,子表的个数为 m+1

typedef struct WORD_b {

WORD_b *llink; //头部域,指向前驱结点 int tag; // 块标志, 0 :空闲, 1 :占用。 int skval; // 块大小,值为 2 的幂次 k

WORD_b *rlink; //头部域,指向后继结点 OtherType other; // 字的其他部分} WORD_b, head; //WORD :内存字类型,结点的第一个字也称 head

typedef struct HeadNode {

int nodesize; // 该链表的空闲块的大小 WORD_b *first; // 该链表的表头指针} FreeList[m + 1]; // 表头向量类型

Page 28: 数据结构 第八章动态存储管理

8-28 中国科大《数据结构》

8.4 伙伴系统

示例:可利用空间表的初始状态如下图所示,其中示例:可利用空间表的初始状态如下图所示,其中 mm 个子表都为空个子表都为空表,只有大小为表,只有大小为 22mm 的链表中有一个结点,即整个存储空间。的链表中有一个结点,即整个存储空间。

(a) 表的初始状态

nodesize first

20

21

2k

2m 0 m

伙伴系统中的可利用空间表

Page 29: 数据结构 第八章动态存储管理

8-29 中国科大《数据结构》

8.4 伙伴系统

分配算法分配算法当用户提出大小为当用户提出大小为 nn 的内存请求时,首先在可利用表上寻的内存请求时,首先在可利用表上寻

找结点大小与找结点大小与 nn 相匹配的子表,若此子表非空,则将子表中任意一相匹配的子表,若此子表非空,则将子表中任意一个结点分配之即可;若此子表为空,则需从结点更大的非空子表中个结点分配之即可;若此子表为空,则需从结点更大的非空子表中去查找,直至找到一个空闲块,则将其中一部分分配给用户,而将去查找,直至找到一个空闲块,则将其中一部分分配给用户,而将剩余部分插入相应的子表中剩余部分插入相应的子表中

Page 30: 数据结构 第八章动态存储管理

8-30 中国科大《数据结构》

8.4 伙伴系统

算法实现WORD_b AllocBuddy (FreList &avail, int n) { //avail[0..m] 为可利用空间表, n 为申请分配量,若有不小于 n 的空 // 闲 / 块,则分配相应的存储块,并返回其首地址;否则返回 NULL

for (k = 0; k <= m && (avail[k].nodesize<n+1||!avail[k].first);++k); // 查找满足分配要求的子表 if (k > m) // 分配失败返回 NULL

return NULL; else // 进行分配 { pa = avail[k].first; // 指向可分配子表的第一个结点 pre = pa- >llink; // 分别指向前驱和后继 suc = pa- >rlink; if (pa = = suc) // 分配后该子表变成空表 avail[k].first = NULL; else { //从子表中删去 *pa 结点 pre- >rlink = suc; suc- >llink = pre; avail[k].first = suc;

}

for (i=1; avail[k-i].nodesize>=n+1; ++i) { pi = pa + 2k-i; pi- >rlink = pi; pi- >llink = pi; pi- >tag = 0; pi- >kval = k- i; avail[k-i].first = pi; } // 将剩余块插入相应子表 pa- >tag = 1; pa- >kval = k- (――i); } // else

return pa;} // AllocBuddy

Page 31: 数据结构 第八章动态存储管理

8-31 中国科大《数据结构》

8.4 伙伴系统 例子:例子:

假设分配前的可利用空间表的状态如下图所示。若 2k-1<n≤2k-1 ,又第 k+ 1 个子表不空,则只要删除此链表中第一个结点并分配给用户即可;

分配前的表

20

2k-1

2m

0 K2k 0 K 0 K

Page 32: 数据结构 第八章动态存储管理

8-32 中国科大《数据结构》

8.4 伙伴系统

若 2k-2 < n ≤2k-1-1 ,此时由于结点大小为 2k-1 的子表为空,则需从结点大小为 2k 的子表中取出一块,将其中一半分配给用户,剩余的一半作为一个新结点插入在结点大小为 2k-1 的子表中,如下图所示。

(b) 分配后的表

20

2k-1

2m

2k 0 K 0 K

0 K-1

Page 33: 数据结构 第八章动态存储管理

8-33 中国科大《数据结构》

8.4 伙伴系统

若 2k-i-1 < n ≤2k-i- 1( i 为小于 k 的整数),并且所有结点小于 2k 的子表均为空,则同样需从结点大小为 2k 的子表中取出一块,将其中 2k-i 的一部分分配给用户,剩余部分分割成若干个结点分别插入在结点大小为 2k-i、 2k-i+1、…、 2k-1 的子表中。

Page 34: 数据结构 第八章动态存储管理

8-34 中国科大《数据结构》

8.4 伙伴系统

回收算法回收算法 伙伴:是指由同一个大的空闲块分裂成的两个大小相等的存储伙伴:是指由同一个大的空闲块分裂成的两个大小相等的存储

区,这两个由同一大块分裂出来的小块就称之“互为伙伴”。区,这两个由同一大块分裂出来的小块就称之“互为伙伴”。 起始地址为起始地址为 pp ,大小为,大小为 22kk 的内存块,其伙伴的起始地址为:的内存块,其伙伴的起始地址为:

p + 2k ( 若 p MOD 2k+1 = 0)buddy (p, k) =

p- 2k ( 若 p MOD 2k+1 = 2k)

Page 35: 数据结构 第八章动态存储管理

8-35 中国科大《数据结构》

8.4 伙伴系统

算法思想算法思想 回收空闲块时,首先判别其伙伴释放为空闲块,若否,则只要将回收空闲块时,首先判别其伙伴释放为空闲块,若否,则只要将

释放的空闲块简单插入在相应子表中即可;若是,则需在相应子表释放的空闲块简单插入在相应子表中即可;若是,则需在相应子表中找到其伙伴并删除之,然后再判别合并后的空闲块的伙伴是否是中找到其伙伴并删除之,然后再判别合并后的空闲块的伙伴是否是空闲块。依此重复,直到归并所得空闲块的伙伴不是空闲块时,再空闲块。依此重复,直到归并所得空闲块的伙伴不是空闲块时,再插入到相应的子表中去。插入到相应的子表中去。

例子例子 例如,假设整个可利用内存区大小为例如,假设整个可利用内存区大小为 210210 == 10241024 (地址从(地址从 00 到到

10231023 ),则大小为),则大小为 2828 ,起始地址为,起始地址为 512512 的伙伴块的起始地址为的伙伴块的起始地址为 77

6868 ;大小为;大小为 2727 ,起始地址为,起始地址为 384384 的伙伴块的起始地址为的伙伴块的起始地址为 256256 。。

Page 36: 数据结构 第八章动态存储管理

8-36 中国科大《数据结构》

习题

本章习题参见教师网页:本章习题参见教师网页:http://staff.ustc.edu.cn/~leeyihttp://staff.ustc.edu.cn/~leeyi