通常情况下,一个高级操作系统必须要给进程提供基本的、能够在任意时刻申请和释放任意大小内存的功能,就像malloc 函数那样,然而,实现malloc 函数并不简单,由于进程申请内存的大小是任意的,如果操作系统对malloc 函数的实现方法不对,将直接导致一个不可避免的问题,那就是内存碎片。

内存碎片就是内存被分割成很小很小的一些块,这些块虽然是空闲的,但是却小到无法使用。随着申请和释放次数的增加,内存将变得越来越不连续。最后,整个内存将只剩下碎片,即使有足够的空闲页框可以满足请求,但要分配一个大块的连续页框就可能无法满足,所以减少内存浪费的核心就是尽量避免产生内存碎片。

针对这样的问题,有很多行之有效的解决方法,其中伙伴算法被证明是非常行之有效的一套内存管理方法,因此也被相当多的操作系统所采用。

伙伴算法,简而言之,就是将内存分成若干块,然后尽可能以最适合的方式满足程序内存需求的一种内存管理算法,伙伴算法的一大优势是它能够完全避免外部碎片的产生。什么是外部碎片以及内部碎片,前面博文slab分配器后面已有介绍。申请时,伙伴算法会给程序分配一个较大的内存空间,即保证所有大块内存都能得到满足。很明显分配比需求还大的内存空间,会产生内部碎片。所以伙伴算法虽然能够完全避免外部碎片的产生,但这恰恰是以产生内部碎片为代价的。

Linux 便是采用这著名的伙伴系统算法来解决外部碎片的问题。把所有的空闲页框分组为 11 块链表,每一块链表分别包含大小为1,2,4,8,16,32,64,128,256,512 和 1024 个连续的页框。对1024 个页框的最大请求对应着 4MB 大小的连续RAM 块。每一块的第一个页框的物理地址是该块大小的整数倍。例如,大小为 16个页框的块,其起始地址是 16 * 2^12 (2^12 = 4096,这是一个常规页的大小)的倍数。

下面通过一个简单的例子来说明该算法的工作原理:

假设要请求一个256(129~256)个页框的块。算法先在256个页框的链表中检查是否有一个空闲块。如果没有这样的块,算法会查找下一个更大的页块,也就是,在512个页框的链表中找一个空闲块。如果存在这样的块,内核就把512的页框分成两等分,一般用作满足需求,另一半则插入到256个页框的链表中。如果在512个页框的块链表中也没找到空闲块,就继续找更大的块——1024个页框的块。如果这样的块存在,内核就把1024个页框块的256个页框用作请求,然后剩余的768个页框中拿512个插入到512个页框的链表中,再把最后的256个插入到256个页框的链表中。如果1024个页框的链表还是空的,算法就放弃并发出错误信号。

简而言之,就是在分配内存时,首先从空闲的内存中搜索比申请的内存大的最小的内存块。如果这样的内存块存在,则将这块内存标记为“已用”,同时将该内存分配给应用程序。如果这样的内存不存在,则操作系统将寻找更大块的空闲内存,然后将这块内存平分成两部分,一部分返回给程序使用,另一部分作为空闲的内存块等待下一次被分配。

以上过程的逆过程就是页框块的释放过程,也是该算法名字的由来。内核试图把大小为 b 的一对空闲伙伴块合并为一个大小为 2b 的单独块。满足以下条件的两个块称为伙伴:

  • 两个块具有相同的大小,记作 b
  • 它们的物理地址是连续的
  • 第一块的第一个页框的物理地址是 2 * b * 2^12 的倍数

该算法是迭代的,如果它成功合并所释放的块,它会试图合并 2b 的块,以再次试图形成更大的块。

下面通过一个例子,来深入地理解一下伙伴算法的真正内涵(下面这个例子并不严格表示Linux 内核中的实现,是阐述伙伴算法的实现思想):

假设系统中有 1MB 大小的内存需要动态管理,按照伙伴算法的要求:需要将这1M大小的内存进行划分。这里,我们将这1M的内存分为 64K、64K、128K、256K、和512K 共五个部分,如下图 a 所示

1.此时,如果有一个程序A想要申请一块45K大小的内存,则系统会将第一块64K的内存块分配给该程序(产生内部碎片为代价),如图b所示;

2.然后程序B向系统申请一块68K大小的内存,系统会将128K内存分配给该程序,如图c所示;

3.接下来,程序C要申请一块大小为35K的内存。系统将空闲的64K内存分配给该程序,如图d所示;

4.之后程序D需要一块大小为90K的内存。当程序提出申请时,系统本该分配给程序D一块128K大小的内存,但此时内存中已经没有空闲的128K内存块了,于是根据伙伴算法的原理,系统会将256K大小的内存块平分,将其中一块分配给程序D,另一块作为空闲内存块保留,等待以后使用,如图e所示;

5.紧接着,程序C释放了它申请的64K内存。在内存释放的同时,系统还负责检查与之相邻并且同样大小的内存是否也空闲,由于此时程序A并没有释放它的内存,所以系统只会将程序C的64K内存回收,如图f所示;

6.然后程序A也释放掉由它申请的64K内存,系统随机发现与之相邻且大小相同的一段内存块恰好也处于空闲状态。于是,将两者合并成128K内存,如图g所示;

7.之后程序B释放掉它的128k,系统也将这块内存与相邻的128K内存合并成256K的空闲内存,如图h所示;

8.最后程序D也释放掉它的内存,经过三次合并后,系统得到了一块1024K的完整内存,如图i所示。

 更多Linux内核源码高阶知识请加开发交流Q群篇【318652197】获取,进群免费获取相关资料,免费观看公开课技术分享,入群不亏,快来加入我们吧~

学习资料免费领

学习直通车

十年码农教你学习,linux内存管理——内存管理架构相关推荐

  1. 老码农教你学英语(学习素材)

    对于咱们这些高端大气.时刻需要和国际接轨的码农,英语的重要性自然是毋庸置疑的.尤其是那些胸怀大志的潜在大牛们,想在码农行业闯出一片天地,秒杀身边的小弟们,熟练掌握英语更是实现其目标最关键的因素之一.否 ...

  2. 从业5年,教你学习Linux开发

    为什么要学习Linux编程? 其实这个问题很容易回答,因为你要写的程序是跑在Linux下的啊.至于跨平台的程序,你熟哪个就在哪个下开发,效率第一,纠缠平台和工具,纯属吃饱了没事干闲的.其实Linux编 ...

  3. 转载老码农教你学英语

    作者微博:@老码农的自留地 对于咱们这些高端大气.时刻需要和国际接轨的码农,英语的重要性自然是毋庸置疑的.尤其是那些胸怀大志,想在码农行业闯出一片天地,成为秒杀身边小弟们的潜在大牛们,熟练掌握英语更是 ...

  4. 图灵社区 : 阅读 : 十年码农聚会报道——让高龄老码农social起来

    图灵社区 : 阅读 : 十年码农聚会报道--让高龄老码农social起来 图灵社区 : 阅读 : 十年码农聚会报道--让高龄老码农social起来 十年码农聚会报道--让高龄老码农social起来 推 ...

  5. 老码农教你在 StackOverflow 上谈笑风生

    老码农教你在 StackOverflow 上谈笑风生 本文作者: 伯乐在线 - 老码农 . 欢迎加入伯乐在线 专栏作者. 作为一个高大上的码农,你肯定用到过 StackOverflow,必须的.会有人 ...

  6. Linux学习——Linux文件与目录管理

    Linux学习--Linux文件与目录管理 实验内容 实验目的 实验指导 实验内容 练习Linux文件和目录操作命令. 实验目的 掌握文件与目录管理命令 掌握文件内容查阅命令 实验指导 文件与目录管理 ...

  7. 易学笔记--十年码农的程序路(交流请加昵称号)

    先自我嘲笑一番 本人程序猿一枚,十年IT工作经验,现在在某大型企业任高级系统工程师,目前主要负责公司新技术选型.新架构的落地实现以及新技术的培训推广工作,当然少不了项目管理以及培养新人的任务. 工作前 ...

  8. 十年码农:我在加入亚马逊 5 个月后选择离职了

    [CSDN编者按]编程生涯走过十年之后,很多开发者都会选择更好的工作机遇,以期获得更高的晋升.更佳的待遇.以及更多的挑战.而亚马逊作为巨头之一,也是不少人梦寐以求的公司之一.本文的作者作为一位有着十年 ...

  9. 十年老码农吐血经验:跳槽千万不能选高年终低base的公司,超过15薪就要慎重!...

    低base高年终VS高base低年终,哪个更好? 一个工作十年的老码农总结了自己的经验:跳槽千万不能选年终月数多的公司,超过15薪就要好好掂量掂量.能选外企就选外企,奖金基本就是一个月,不会坑你. 一 ...

最新文章

  1. Lowbit Sum 规律
  2. Postgres多版本控制
  3. CPL DPL RPL的区别 一致性代码段和非一致性代码段
  4. 问题:org.gradle.process.internal.ExecException: Process 'command 'C:\Program Files\Java\jdk1.8.0
  5. android gridlayout动态添加_Android-TabLayout-动态设置TabItem的背景Shape.有坑.......
  6. java 图文生成图片_java生成图片
  7. SDUT oj 选拔赛1 迷之好奇
  8. gitlab 项目分支管理的一种策略
  9. JavaSE基础_java简介和环境搭建_2
  10. 清理rms客户端信息
  11. 区块链开发(三)以太坊客户端命令行选项汇总
  12. iphone长截图哪个软件好_看完长知识了!苹果手机也能截长图,原来iPhone截屏还能这样玩...
  13. Docker 容器内体验 WebSSH
  14. MODBUS寄存器从40000开始而不从0开始,有什么特别的说法吗,还是仅仅是大家都习惯
  15. 24款神级插件,让你的 vscode更牛
  16. input选择框样式修改与自定义
  17. 阻止创建“迅雷下载“目录
  18. 转载:2016.3.15 回忆录
  19. 参考文献是会议论文应该什么格式?
  20. ArcFace:Insight Face

热门文章

  1. 高效添加领英好友,拓展领英人脉的几种方法
  2. LVGL字定义字体占用空间分析 与 MP5芯片选型
  3. python多线程并发请求
  4. 雅思底层之一,五分到六分
  5. 神武手游宠物打书模拟器
  6. 函数查找工具 —— 使用介绍
  7. 电脑蓝牙闪断闪连解决办法
  8. 虚拟机计算机无法启动,vmware15创建虚拟机,vmware虚拟机无法启动
  9. 剑网三哪个网站服务器人多,《剑网3缘起》这么火?服务器快挤爆了!
  10. 二十一Redis集群