《Operating System:Three Easy Pieces》阅读笔记<九>——空间管理(free-space-management)

247 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

空间管理

在进程中,具体的讲,是在地址空间的heap区,存在许多空闲内存,或者在操作系统上,进程内存空间之中也有许多未被分配的空闲内存。这两种空闲内存相对对象不同,但是都面临相同的问题,即怎样合理安排的内存空间的位置,才能让进程的内存申请变的更加高效。这引出了一类问题,即空闲空间管理问题(free-space-management)

对于操作系统级的空间管理之前已经有所涉及,我们以更加简单的情况,即进程中heap区的空闲内存管理为模型,分析怎样管理内存。

首先是三个功能方面的底层机制,首先是splitting(分离)和coalescing(合并)机制,我们抽象进程heap区的空余空间都在free space table这个结构上:

  • 当一片新内存被申请时,splitting机制让一块内存分离出和新内存相同大小的空间以供使用,而剩余空间依然在表里
  • 当两片剩余空间地址上相邻时,coalescing机制让相邻空间合并成更大的一块。

很多时候我们会发现操作系统通过某些数据结构来跟踪系统状态,如何设计数据结构是系统能否高效执行的一个关键因素。

free space table的抽象模型可以看下图。

当进程申请空间时,在free space table上有多块空闲内存可以分配,该将哪一块分配给进程,这是贯穿本节的最关键的问题,因为其对整个系统的内存分配均衡具有重要影响。但是关于这一点的讨论比较困难,因为我们当前的内存模型还不够灵活,现代空间调度算法大多基于我们之后会学到的更加灵活的模型,因此这里不讨论具体的调度算法。而是理解空余空间管理这一问题的性质和早期系统做过的尝试。

第二个机制是跟踪已分配空间的的大小,在使用free()函数时,我们并不需要指定需要释放的空间的大小,只需要把需要释放的变量地址指针传入即可。这是因为一个已分配空间的大小并不是保存在操作系统中,而是就在分配内存的头部,具体来说,free的机制如下图代码所示。

第三个机制是将free space table嵌入到地址空间中,与记录已分配空间的的大小类似,将空余空间的大小保存在空余空间的头部

抽象的,我们可以认为heap中某一段空间的内存模型以及free space table在地址空间中嵌入的模型如下图所示

其中free space table以链式形式存储,假如两片空间相邻,则会合并为一个空间。事实上,大部分进程一开始heap空间都是很小的,当需要更多空间时,可以通过system call如sbrk申请增加heap空间。

当一个变量/进程申请空间时,如何安排已有的空间来给出响应的空间是十分重要的,这一方面有许多策略,简单的有如Best Fit、First Fit、Next Fit等,而更复杂更高级的策略有Segregated Lists、Buddy Allocation等。事实上,这个领域到现在还是没有相当统一的优化方法,如果对空间调度器感兴趣的话,可以看一下glibc allocator这个调度器,了解一下现代调度器是怎样调度内存空间的。

例子

以一个简单的free space table为例,当一个大小为15的内存请求到达时,系统用不同的策略给予内存之后table的状态不同