内存受限设备的应用层内存管理(二)
Raveendran Vadakkoot and Neeraj S. Sharma
译 By 郭世龙
3b.分离链表及分配策略
分配策略根据对象的大小可以分成三类。
·大小X的对象的分配,这里X<=M/2
如果被请求的对象的大小是X,这里X=M/2 ,M是页的尺寸,页一般包含多于1个对象。像前面讨论的一样,X属于的“类别”是通过找到2的幂次 ,i和j,这样i < X > =j,来划的,
如果分离列表的头没有空闲空间,会从空闲列表分配一个新的页并把它加入到分离链表的头部(合适的分类)。
·大小X的对象的分配,这里M/2< X <= M
请求一个大小X的块,这里X >M/2,M是页(块)的尺寸。这是一种一个页只能容纳一个元素的情况。
一个新的页会被从空闲列表分配并被加入到分离链表的头部。
·大小X的对象的分配,这里X >M/2
1.跨越单元(cell)的多个块
2.他们能或不必是分离链表的组成部分
这是一种多页块的情况。多页块浪费了内存。但是,内存受限应用程序遇到大块内存请求的情况是十分不可能的。 被这些块占用的页的数目通常是(X/M)+1.多页块不得不分开处理。他们跨越页的数目可以通过查看容纳他们的第一个页的目录很容易的识别。
图8为上图的分配方案给出了一种可能的内存布局。
图8分离链中的内存布局
在图8中,黄色的页持有大小为X的对象,这里1<=X<=16,而蓝色页持有大小为Y的对象,这里16<Y<=32. Head1从中间某点开始链接连续打内存块的开始部分的小块,依次链连到续大内存块的最后页。但是对于,大小为Y的对象的链向前移动without having 后向链。两个页之间的白色块或是是没有被分配或者是分配后被回收的。
4.多页对象和边界标签
一个空闲链表一般是一组空闲页构成的一个链。出现在空闲链表中的页可能是连续的也可能是分散的。在图9中,你可以注意到标记为红色的单元是空闲块。前两个块只有一页,而链中的第3个块是一组连续的页。跨越多个页的对象(对象大小为X,这里X>M,M是页的大小)有一组连续的页。

边界标签
边界标签被用在对象跨越多个页的情况。多页对象的最后一页有一个指向块中第一页的指针。这个典型的被用在回收过程中的页的接合。图10中,数据是一个n个页的连续块,数据是多页对象。最后的页(页n),与第一页(页1)有一个链接。这个链是边界标签。

图10:内存回收时的边界标签指针
5.回收和接合
在单元回收中,检查邻近的页是否可以与空闲的页合并。在图11所示的内存布局中,桔红色的块是空闲块,很容易注意到它能与左边的页合并。但是不可能与右边的块合并,因为它仍然在使用中。

图11:合并邻近空闲内存块
在这个内存管理讨论的算法中,与左页接合很容易,用户需要做的是增加这个空闲页的大小到其左边的块。换句话说,桔红色块的大小事2M(这里M是页的大小)并且它左侧的空白块大小为a×M。那么一旦橘红色的块空闲,用户将有(a+2)×M大小的连续块如图12所示。每页一页都有一个位图,它用来标识是否空闲。多页块的最后页总是有一个指向头的指针。这被称为边界标签。在单页块的情况中,边界标签被设置为NULL或者指向自身。根据边界标签,用户可以到达一个页的头。无论是单页块还是多页块,头都记录了块的大小。一个单页块大小是M而多页块大小是a×M,这里a是这个块的页数。

图12:空闲块合并之后的内存块
与右侧块的接合有一点难。首先,你必须知道右边的单元指向的是什么,然后让这个空闲单元指向右边单元所指向。图13中,紫色的单元是回收的单元。邻近右侧的单元是一个空闲单元,它指向下一个空闲单元。
在这种情况下,用户:
1).首先接合这个单元和其右边的一个,然后接合左边的一个,或者
2).首先接合这个单元与左边的一个然后再接合右边的一个。
这里使用的策略是首先接合右边的一个,在图14中,块C指向块E,它是连续内存块的末端。B一被回收,它就首先与块C接合,然后这个接合的块进一步与块A接合。在第一步(就是B与C结合时),B被使指向块E(C块指向的块,直到合并)如图15所示。块C的大小被加到块B上。这之后,一个做检验,看这个接合快(B+C)是否能被进一步与块A(在这里可以)。如图16所做的。
注意:创建了一个指向E的中间指针,然后释放了。

图13:初始内存块

图14:右合并之后的内存块

图15:左合并之后的内存块
(待续未完....)