第17章 空闲空间管理
本章要解决的问题:如何管理空闲空间?什么策略可以让碎片最小化?
17.1 假设
- 假定基本的接口就像malloc()和free()提供的那样。
- 主要关系外部碎片
- 内存一旦被分配给客户,就不可以被重定位到其他位置。
- 分配程序所管理的是连续的一块字节区域。
17.2 底层机制
分割与合并
追踪已分配空间的大小
嵌入空闲列表
让堆增长:大多数传统的分配程序会从很小的堆开始,当空间耗尽时,再向操作系统申请更大的空间。
17.3 基本策略
最优匹配:选择最接近用户请求大小的块,从而尽量避免空间浪费
最差匹配:与最优匹配相反,研究表明其表现非常差
首次匹配:找到第一个足够大的块
下次匹配:多维护一个指针,指向上一次查找结束的位置,避免首次匹配那种对列表开头频繁的分割
17.4 其他方式
分散空闲列表:
如果某个应用程序经常申请一种(或几种)大小的内存空间,那就用一个独立的列表,只管理这样大小的对象。
这种方法的好处显而易见。通过拿出一部分内存专门满足某种大小的请求,碎片就不再 是问题了。而且,由于没有复杂的列表查找过程,这种特定大小的内存分配和释放都很快。
伙伴系统:
因为合并对分配程序很关键,所以人们设计了一些方法,让合并变得简单,一个好例子就是二分伙伴分配程序。
在这种系统中,空闲空间首先从概念上被看成大小为 2N 的大空间。当有一个内存分配 请求时,空闲空间被递归地一分为二,直到刚好可以满足请求的大小(再一分为二就无法 满足)。这时,请求的块被返回给用户。在下面的例子中,一个 64KB 大小的空闲空间被切 分,以便提供 7KB 的块:
请注意, 这种分配策略只允许分配 2 的整数次幂大小的空闲块,因此会有内部碎片(internal fragment) 的麻烦。
伙伴系统运转良好的原因,在于很容易确定某个块的伙伴。怎么找?仔细想想上面例子中的各个块的地址。如果你想得够仔细,就会发现每对互为伙伴的块只有一位不同,正是这一位决定了它们在整个伙伴树中的层次。
17.5 小结
本章我们讨论了最基本的内存分配程序形式。
“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情”