简介:
Linux内核使用二进制伙伴算法来管理和分配物理内存页面, 在内核初始化完成之后, 内存管理的责任就由伙伴系统来承担.,该算法由Knowlton设计, 后来Knuth又进行了更深刻的描述.
核心思想:将内存按2的幂进行划分,组成若干空闲链表;查找该链表找到能满足进程需求的最佳匹配块。
算法基本步骤:
将整个可用的内存空间看做一个整体,大小为: 2^u(2的u次方)
假设现在一个进程申请的空间为s:
如果满足2^(u-1) < s <= 2^u
,那么就将这整块内存分配给该进程
否则,就将这块内存划分为两个大小相等的伙伴,假设此时这两伙伴分别为A块和B块,大小都为2^(u-1)
然后,继续判断A块内存是否满足进程的需求,此时是一样的,需要判断s是否大于A块内存的一半,且小于A块内存,如果满足,就将A块划分出去,如果不满足,那么继续将A块内存划分成2个伙伴,直到能找到一块内存大于s,且它的一半比s小,则把这块内存分配给该进程。
假如,此时A’满足分配要求,则将其余空闲内存块A’’ B用链表组织在一起,等待其余进程申请物理内存。如果不满足,则继续将A‘划分为伙伴,相当于是个递归的过程。
实例:
此时系统只剩3个空闲块,即绿色部分,用链表将这三个部分组织起来,此时又来进程B申请物理内存,大小为240K:根据上面的算法步骤,不难推导出,将空闲的256K分配给进程B,因为256/2 < 240 < 256:
此时进程C申请64K的物理内存,根据上述步骤,不难得出,链表最前面是空闲的128K的这个内存块,然后将128K切割成2个伙伴,将其中一个伙伴分配出去:
此时进程D申请256K的物理内存:
申请的过程大概是这样的。
关于释放时,比较有意思,如果释放的内存块之前是伙伴关系的话,会自动将内存块合并起来,举个例子:
红色的64被释放,他与绿色的64是伙伴关系,是被128K划分而来的,那么他俩会被结合成一块新的空闲内存。
同样,如果红色128K被释放,他和左边2个64合起来的内存块是伙伴关系,那么就将128+64+66合并成一块新的空闲内存;
…
直到左边三块红色(128K 64K 256k)的都被释放,右边的一块256k的被释放,左右两边是伙伴关系,最终又形成一块新的完整的空闲内存,即刚开始进行分配的那1M内存块。
实际上,内存释放后,如果他的伙伴关系的内存块空闲的话,就像划分伙伴之前一样组合起来,组合成一块比较大的空闲内存块来满足需求。
感兴趣的话,可以去看老师讲课程,非常感谢分享学习资源的同学:https://www.bilibili.com/video/BV1Gx411Q7ro?p=42