摘 要 本文分析了动态存储管理的特性, 提出了一种利用哈希表的快速查找特性来优化基于伙伴系统动态存储管理器算法的思想,高效地实现了存储管理器的分配和回收算法,具有简单、速度快、克服了大量存储空间的浪费等优点。
1 引言
动态存储管理在实现中体现为一个动态存储分配器(dynamic allocator) 。动态存储分配器的设计目标是尽量减少空间的浪费,减少申请释放存储空间时的时间消耗[1]。理想的动态存储分配器是在不浪费空间,极少的时耗下,能满足任何次序的存储空间申请和释放。由于减少时间消耗与增加空间利用率往往相互矛盾, 现实中理想的分配器是很难甚至是不可能实现的,只能根据特定的环境做出适当的决策。
本文在对当前应用中主要采用的动态存储管理技术进行分析的基础上,提出了一种基于buddy动态存储分配和回收思想,利用哈希查找快速定位最佳可利用空闲块在内存中位置的动态存储管理算法。采用这一算法思想设计的动态存储分配器具有简单、速度快的优点,克服了大量存储空间浪费的问题。
2 动态存储分配技术
对动态存储管理经过多年的研究,已有大量的动态存储管理解决方案和算法提出并应用到不同的系统中。如:顺序搜索、buddy 算法、分类搜索、索引搜索、位图搜索等。其中顺序搜索和分类搜索算法在操作系统动态内存分配中被普遍采用。
采用顺序搜索的动态存储分配器,一般采用“可利用空间队列”avail链接运行中形成的长度不相等的空闲存储块,采用首次适配(first fit) 、下次适配(next fit) 、最佳适配(best fit) 和最差适配(worst fit) 算法顺序搜索适配块。搜索适配块的时间开销依赖于avail 队列长度。优点是简单,存储空间利用率高。缺点是随着系统规模的增大,会形成许多小碎块,使 avail 队列变长,搜索时间将可能增加到不可接受的程度。
采用分类搜索的动态存储分配器,一般按固定大小将存储空间划分为多个相互独立的存储区,每一个存储区包含一条 avail 队列,存储对象在唯一的 avail 中分配空间。优点是申请分配空间时,不需要进行搜索来查找符合要求的空闲块。释放时也没有相邻空闲块合并的要求,提高了系统执行速度,具有良好的可伸缩性。缺点是在每一个存储区都将有一定的存储空间空闲,且相互之间不能共享,造成较为可观的存储空间浪费。这是典型的以空间换时间的作法。并且存储区划分越细,浪费越严重。
另一种动态存储分配办法是将空闲块组织为伙伴系统(buddy system )。伙伴系统规定,无论占用块或空闲块其大小均为2 的k次幂(k为整数)。假设系统的可利用空间容量为2m 个字,则系统开始运行时,整个内存区是一个大小为2m 的空闲块,系统运行中可能会形成若干个空闲块,将相同大小的空闲块都链在的空闲块都链在同一个双重链表中,不同大小空闲块形成k(0=k=m)个空闲块链表。当要分配一长度为n 的存储块时,求i 使2i-1 n ≤2i。若长度为2i 的空闲块已耗尽,则把长为2i+1的空闲块分为等长的两半(一对伙伴),一个用于分配,一个链入长为2i 的链表中。若长为2i+1的空闲块也不存在,则需要对长为2i+2的空闲块进行两次分割,依此类推。由此可见,在最坏情况下, 可能要进行k 次分割才能得到适配块。与一次分配可能要进行多次分割一样,一次回收也可能要进行多次合并。其分配和回收的时间性能取决于查找空闲块的位置和分割、合并空闲块所花费的时间。空间性能远优于分类搜索算法,比顺序搜索算法略差。
3 基于哈希查找的基本思想与结构定义
3.1 基于哈希查找的基本思想
基于哈希查找的基本思想是:利用哈希快速查找优点和空闲块在可利用空间表中的分布规律,构造哈希函数。当请求分配存储空间时,通过查找以空闲块大小为关键字的哈希表选择合适的空闲块链,实现最佳分配策略。
对系统运行可能形成的k个空闲块链表,将头指针组织成一个向量结构,根据链表中空闲块大小确定链表头指针在向量中的位置。
由于申请的空闲块长度 n 要求满足关系2i-1 n ≤2i。因此可定义哈希函数
哈希函数计算结果确定了所申请大小的空闲块对应链表应在向量表中的位置。
3.2 存储结构定义
空闲块结点结构定义,如图1所示。
图1 空闲块结点结构
结点数据类型定义描述
#define n size /*定义size为可利用空间容量,大小为2的次幂*/
typedef struct WORD_NODE
{ int tag; /*块标志,0:空闲,1:占用*/
int kval; /*块大小,值为2的K次幂*/
WORD_NODE *llink,rlink; /*指向前驱、后继结点的指针域*/
OtherType other; /*其它部分*/
}WORD_NODE,head; /*内存字类型,结点的第一个字为head*/
头指针向量表数据类型定义描述
typedef struct HeadNode
{ int nodesize; /*该链表空闲块大小*/
WORD_NODE *first; /*该链表的头指针 */
}FreeList[m+1];/*可利用空间表头向量类型*/
系统初始状态的可利用空间表状如图2所示。
图2 可利用空间表初始状态
4 分配与回收算法
4.1 分配算法
当用户申请分配长度为n 的存储块时, 求 i = HASH(n),若FreeList[i].first不空,只要删除此链表中的第一个结点,分配给申请者即可;否则判断FreeList[i+1]所对应的空闲块链表,若不空,则把长为2i+1 的第一个空闲块分为等长的两半(一对伙伴) , 一个用于分配给申请者,另一个链入FreeList[i].first对应的链表中。若FreeList[i+1].first仍然为空,则依次判FreeList[i+2].first,以此类推。假若直到i+k 时,FreeList[i+k].first非空,则需要从该链表中取出一个结点,将大小为2k的一部分分配给申请者,剩余部分分割成若干个大小分别为2i+1、2i+2、…、2i+k-1的结点插入到对应大小的链表中。
算法描述
WORD_NODE *AllocBuddy(FreeList &avail,int n)
{/*申请容量为n的存储空间*/
j = HASH(n);
while(!avail[j].first&&j=m) j++;
if(j m)return NULL;
i = j;
pa = avail[i].first;
pre = pa-llink;suc = pa-rlink;
if(pa == suc) avail[i].first = NULL;
else {从子表删去*pa结点;}
for(k = j;k i;k++)
{ pi = pa + 2i-k;
pi-rlink = pi;
pi-llink = pi;
pi-tag = 0;
pi-kval = i-k;
avail[i-k].first = pi
}
Pa-tag = 1;
pa-kval = i-(--k);
Return pa;
}
4.2 回收算法
回收空闲块时,若该回收块的伙伴也为空闲块,则需将他们合并成大的空闲块。然后再判断合并后的空闲块的伙伴是否为空闲块,若是则继续合并。否则只要将释放的空闲块简单地插入到相应空闲块链表中即可。
设大小为2i的空闲块起始地址为 p,其伙伴块的起始地址可采用下式计算:
若p MOD 2i+1 =0,则其伙伴块的起始地址为p+2i
若p MOD 2i+1 =2i,则其伙伴块的起始地址为p-2i
例如,假设p为大小为2i的空闲块的起始地址,当p MOD 2i+1 =0时,起始地址为p和p+2i的两个空闲块互为伙伴;当p MOD 2i+1 =2i时,起始地址为p和p-2i的两个空闲块互为伙伴。利用该性质可方便地实现空闲块的合并与回收。这里仅给出回收算法的描述
void FreeBuddy(&avail,*addr,n)
{ /*回收长度为n,起始地址为addr的块*/
置回收块标志tag为0,块长kval为n;
求回收块的伙伴地址buddy=addr%(2* n)?(addr- n):addr+n);
求回收块应在头指针向量中的位置i=HASH(n);
如果avail[i].first为空,表明该块没有伙伴,直接插入到插入到该链表中;
否则{
在当前链表中寻找伙伴(地址为buddy的块);
如果存在伙伴,并且该伙伴是当前链表中唯一大小为2i的空闲块,则置avail[i].first为空;
否则,从当前链表中删去伙伴;
修改合并后的新空闲块起始地址(addr或buddy)以及合并块kval的值为2*n;
以新地址和新块长为参数,递归调用FreeBuddy函数,继续调用并合并伙伴块;
}
将得到的最后合并块插入到对应头指针向量所对应的空闲块链表中;
}
5 结束语
操作系统动态内存管理方法很多,它们各有其优缺点,各有其适用情形。选择合理的存储分配和管理方案必须建立在设计者对硬件平台和系统中动态内存的申请释放流进行科学评价和分析的基础上。
本文所提出的存储管理算法的时间性能主要取决于查找空闲块的位置和分割、合并空闲块所花费的时间。采用哈希快速定位方法查找空闲块的时间为常量,合并空闲块的时间开销为k的线性阶,分配、释放空闲空间的时耗极小且相对稳定,比较适用于嵌入式实时系统。但由于释放存储空间时只归并互为伙伴的空闲块,容易产生存储碎片。
参考文献
[1] Andrew S. Tanenbaum & Albert S. Woodhull. Operating Systems Design and Implementation[M]. 电子工业出版社. 2001.4
吴晓勇,曾家智.操作系统内核中动态内存分配机制的研究.成都信息工程学院学报[J],2005;20(1);27~30
郭福顺,王世铀,藏天仪.一种动态存储管理机制.计算机研究与发展[J]. 1999;36(1);62~66
石峰,刘坚.动态存储错误的静态检测方法研究. 计算机工程与应用[J].2004(19), 104-106.
刘佳,张毅.基于流数据的动态存储技术. 燕山大学学报[J].2005(4), 344-347.
David EVANS, David Larochelle Improve .Security Using Extensible Light weight Static Analysis[J].IEEE Software,2002,19(1)