使用指南阅读和理解linux内核时 http://www.johnchukwuma.com/training/UnderstandingTheLinuxKernel3rdEdition.pdf
我在Buddy系统中尝试理解页面分配和释放的内容。
Linux采用的解决外部碎片的技术 问题是基于众所周知的伙伴系统算法。全部免费 页面框架被分组为11个包含组的块列表 1,2,4,8,16,32,64,128,256,512和1024个连续页面 帧,分别。 [第8.1.7节]
这非常有意义,因为现在Linux可以快速提供分配请求,因为不同的块大小已经准备好用于不同的块大小请求。
现在,假设系统已启动,并且所有可用页面都是免费的,并按上述方式分组给这11个组。现在让我们考虑一个场景,其中一个过程需要一个订单1的页面,然后释放它。根据免费算法 -
while (order < 10)
{
buddy_idx = page_idx ^ (1 << order);
buddy = base + buddy_idx;
if (!page_is_buddy(buddy, order))
break;
list_del(&buddy->lru);
zone->free_area[order].nr_free--;
ClearPagePrivate(buddy);
buddy->private = 0;
page_idx &= buddy_idx;
order++;
}
所以根据这个和我的场景,订单1块(第一个分配)将与另一个订单1块合并到一个订单2的块中,尽管两个订单1块没有从订单2中拆分分配阶段的大块。
这样,如果我继续分配然后释放一个块,很快系统将达到一个状态,其中所有内存块都是最大的顺序,这似乎效率不高。我原本以为只有当那些伙伴先前从更大的订单块中拆分时才会合并两个好友,这样就会尽可能地保留初始默认状态,整个系统将保持高效。
我错过了什么吗?这段代码有可能错了吗?我不知道此代码提供的其他优势吗?
答案 0 :(得分:0)
当有大量最小的订单块可用时,假设这样的初始状态可能有点可疑。如果我没记错的话,应该从查看最小(相同大小)的组开始分配内存块,然后查看更高阶的组来查找空闲块。如果找到的块大于所需的块,则将其拆分,并更新相应的组。这并不是那么明显,但是当只有最高阶块可用时,整个过程可能从初始状态开始。
我在文献中可以遇到的一些例子几乎描绘了初始状态的相同图景。维基百科上可以找到一个雄辩的例子:https://en.wikipedia.org/wiki/Buddy_memory_allocation#In_practice。图表和描述对典型情况有所了解。
总而言之,我找不到任何关于“初始默认状态”假设的证据。将较小的块从较大的块中分离时效率降低的想法是最模糊的,并且可能需要单独的谈话。
修改强>:
从内核的角度来看,初始状态可能与您的假设过程所看到的初始状态不同。比如,系统启动,并且在某一点上有一块内存。但是,您的假设过程并非一个人 - 当然。在进程能够开始分配和释放任何内存块之前,内存分配可能会发生很大的变化。可以肯定的是,内核或者其大多数子系统在初始化期间会请求大量不同大小的内存块,并且内核将占用大量的块(相当于整个过程)正常运行时间)。因此,重点是,当您的流程开始时,伙伴系统可能会“热身”,实际上,足够的小块可用。但是,页面的好友(由您的流程获取)仍将由各种子系统拥有,并且,一旦您的流程决定释放其页面,那些< em>好友将不会被批准为合并准备就绪,即摘录中的page_is_buddy()
将产生错误。当然,如果你的进程确实成功地获取现有的空闲块而不分割高阶块,那么整个场景可能都是真的。
所以,关键是你对初始伙伴分布的假设可能不是真正的初始状态。它只能是一个“热身”状态,你确实可能有小块但他们的好友会忙,因此应该阻止所描述的无法控制合并的假设过程。 / p>
P.S。以下是page_is_buddy()
的{{3}}。