Linux是如何避免内存碎片的?

在网上看到这个面试题,参考答案是这样的:

  1. 伙伴算法,用于管理物理内存,避免内存碎片;
  2. 高速缓存Slab层用于管理内核分配内存,避免碎片。

故继而去深入了解了一波,做了一个粗略的整理:

内存碎片问题

  • 频繁地请求和释放不同大小的内存,必然导致内存碎片问题的产生,结果就是当再次要求分配连续的内存时,即使整体内存是足够的,也无法满足连续内存的需求。该问题也称之为外碎片(external fragmentation)。
  • 解决方案:
  • 避免外碎片的方法有两种:
    1、利用分页单元把一组非连续的空闲页框映射到连续的线性地址
    2、开发一种适当的技术来记录现存的空闲的连续页框块的情况,以尽量避免为满足对小块的请求而分割大的空闲快
  • 第一种方案的意思是,我们使用地址转换技术,把非连续的物理地址转换成连续的线性地址。
  • 第二种方案的意思是,开发一种特有的分配技术来记录下来空闲内存的情况,从而解决内存碎片问题。
  • Linux采用了第二种方案,因为在某些情况下,系统的确需要连续的物理地址(DMA处理器可以直接访问总线)。

这里先对Linux内存管理做一个简单介绍

  • linux kernel 通过把整个物理内存划分成以一个个page进行管理,管理器就是伙伴系统,它的最小分配单元就是page。但是对于小于page的内存分配,如果直接分配一个page,是一个很大的浪费。linux kernel 通过slab来实现对小于page大小的内存分配。slab把page按2的m次幂进行划分一个个字节块,当kmalloc申请内存时,通过slab管理器返回需要满足申请大小的最小空闲内存块。
  • slub主要是针对slab的对象管理数据的优化版本,相比于slab,slub提供更小的管理成本开销。而且slub对多核系统的支持也更加友好。细节这里就不展开讲。
  • 所以kernel的内存管理是个2层分层系统,从下往上依次为:
  • 第一层为全部物理内存:其管理器为伙伴系统,最小管理单位为page;
  • 第二层为slab page:其管理器为slab/slub,最小管理单位为2的m次幂的字节块;

伙伴系统(buddy system)

  • Linux采用著名的伙伴系统(buddy system)算法来解决外碎片问题。把所有的空闲页框分组为11个块链表,每个链表分别包含大小为1,2,4,8,16,32,64,128,256,512,1024个连续的页框,对1024个页框的最大请求对应着4MB大小的连续RAM(每页大小为4KB),每个块的第一个页框的物理地址是该块大小的整数倍,例如,大小为16个页框的块,其起始地址是16*2^12的倍数。
    我们通过一个例子来说明伙伴算法的工作原理,假设现在要请求一个256个页框的块(1MB),算法步骤如下:
    • 在256个页框的链表中检查是否有一个空闲快,如果没有,查找下一个更大的块,如果有,请求满足。
    • 在512个页框的链表中检查是否有一个空闲块,如果有,把512个页框的空闲块分为两份,第一份用于满足请求,第二份链接到256个页框的链表中。如果没有空闲块,继续寻找下一个更大的块。
    下图比较形象地描述了该过程。

    页的请求
    以上过程的逆过程,就是页框块的释放过程,也是该算法名字的由来,内核试图把大小为B的一对空闲伙伴块合并为一个2B的单独块,满足以下条件的两个块称之为伙伴:
    • 两个块具有相同的大小
    • 他们的物理地址是连续的
    第一块的第一个页框的物理地址是2 * B * 2^12
    该算法是递归的,如果它成功合并了B,就会试图去合并2B,以再次试图形成更大的块。

高速缓存Slab层

  • slab是Linux操作系统的一种内存分配机制。其工作是针对一些经常分配并释放的对象,如进程描述符等,这些对象的大小一般比较小,如果直接采用伙伴系统来进行分配和释放,不仅会造成大量的内存碎片,而且处理速度也太慢。
  • 而slab分配器是基于对象进行管理的,相同类型的对象归为一类(如进程描述符就是一类),每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免这些内碎片。slab分配器并不丢弃已分配的对象,而是释放并把它们保存在内存中。当以后又要请求新的对象时,就可以从内存直接获取而不用重复初始化。
  • 对象高速缓存的组织如右下图所示,高速缓存的内存区被划分为多个slab,每个slab由一个或多个连续的页框组成,这些页框中既包含已分配的对象,也包含空闲的对象。
  • 在cache和object中加入slab分配器,是在时间和空间上的折中方案。

  • 另外为了解决多核和NUMA架构下效率问题,slab管理器kmem_cache又把slab page对象分为2层结构,从下往上依次为:

  • 第一层为NUMA node下cpu共享page:管理器为kmem_cache_node,管理node下的slab对象,解决NUMA架构的内存访问效率问题。当本层的空闲page不足时,从伙伴系统申请空闲page;
  • 第二层为per-cpu专属page:管理器为kmem_cache_cpu,管理cpu专属的slab对象,解决多核竞争问题。当本层的空闲page不足时,从第一层申请空闲page;

slab分配算法

  • slab分配算法采用cache 存储内核对象。当创建cache 时,起初包括若干标记为空闲的对象。对象的数量与slab的大小有关。开始,所有对象都标记为空闲。当需要内核数据结构的对象时,可以直接从cache 上直接获取,并将对象初始化为使用。
  • 下面考虑内核如何将slab分配给表示进程描述符的对象。在Linux系统中,进程描述符的类型是struct task_struct ,其大小约为1.7KB。当Linux 内核创建新任务时,它会从cache 中获得struct task_struct 对象所需要的内存。Cache 上会有已分配好的并标记为空闲的struct task_struct 对象来满足请求。
  • Linux 的slab 可有三种状态:
    满的:slab 中的所有对象被标记为使用。
    空的:slab 中的所有对象被标记为空闲。
    部分:slab 中的对象有的被标记为使用,有的被标记为空闲。
  • slab 分配器首先从部分空闲的slab 进行分配。如没有,则从空的slab 进行分配。如没有,则从物理连续页上分配新的slab,并把它赋给一个cache ,然后再从新slab 分配空间。

资料整理自:
[1] https://baike.baidu.com/item/slab
[2] http://www.cnblogs.com/wahaha02/p/6616957.html
[3] https://www.jianshu.com/p/c4ef33bde4f5

Linux是如何避免内存碎片的相关推荐

  1. 知识整理(你想要的Linux知识都在这里)

    一.基础问题 1.什么是堆内存和栈内存? 答: 我们可以从几个方面来看它们之间的区别 分配方式 栈:由编译器自动分配和释放,一般存放函数的参数.局部变量.临时变量.函数返回地址等 堆:堆内存是由程序员 ...

  2. 操作系统/LINUX/数据库/算法/设计模式/HR面试题集锦

    文章目录 操作系统 1.操作系统特点 2.什么是进程 3.进程 4.进程与线程的区别 5.进程状态转换图 6.进程的创建过程?需要哪些函数?需要哪些数据结构? 7.进程创建子进程,fork详解 8.子 ...

  3. 伙伴系统之避免碎片--Linux内存管理(十六)

    原文链接:https://blog.csdn.net/gatieme/article/details/52694362 日期 内核版本 架构 作者 GitHub CSDN 2016-09-28 Lin ...

  4. C/C++后台开发基础知识

    C和C++语言基础 参考书籍:<C++ primer>,<effective C++>,<STL源码解析>,<深度搜索C++对象模型> extern关键 ...

  5. 作为程序员,如何征战应聘沙场?

    一.自我介绍:往事不堪回首 首先自我介绍,某985院校计算机学院普通硕士.无ACM.挑战杯或者是各种编程大赛获奖经历,无牛逼哄哄的项目经历,无名企实习经历.总之一句话,一个再普通不过的CS硕士.本科期 ...

  6. 2014找工作总结-机会往往留给有准备的人

    出处:http://blog.csdn.net/xiajun07061225/article/details/12844801 其实我的求职过程在十一之前就已经结束了,总体讲比较顺利.参加面试的几家公 ...

  7. C++软件工程师面试考点.md

    C++软件工程师面试考察主要有C++基础(最好也懂Java).数据结构及简单算法.TCP.操作系统.网络编程.Linux基本操作和Shell编程.数据库,设计模式和智力题也会涉及少量. C++基础 参 ...

  8. 嵌入式面试_面试宝典整理(包括内核)

    https://blog.csdn.net/kai_zone/article/details/82021233 (驱动面试题) 1.系统调用read()/write(),内核具体做了那些事情? 参考: ...

  9. C++问题汇总(一)

    1.TCP/IP close_wait状态和time_wait状态. TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭. CLOSE_WAIT状态的生成原因 首先我们知道,如果我们 ...

最新文章

  1. 搞容器,必须考虑这五大安全要素
  2. mysqlsql varchar类型只取前四个_Apache Doris0.12.0 发布,进入 Apache 孵化器后第四个正式版本...
  3. linux kernel的spinlock在armv7和armv8中的不同
  4. 【攻防世界005】parallel-comparator-200
  5. Express应用配置以及统一安装所需依赖和快速创建应用骨架
  6. sql注入_1-8_宽字节注入
  7. cocos2d-x学习 之四
  8. 在vpp中做nat实验
  9. 《匆匆那年》每一集的标题
  10. iOS 自定义图片无限轮播控件
  11. Pulse local frame(画出光脉冲三维动态演化过程)
  12. 微信开发平台应用签名修改多久之后才可以使用
  13. 什么是token,如何使用token
  14. php退出数据库命令,签约1年半!33岁中超旧将正式登陆葡超,时隔16年重回葡萄牙踢球...
  15. 伪干货:应届生找工作与入职心得
  16. 【华为云技术分享】最终,我决定将代码迁出x86架构!
  17. 通达信指标公式常用绘图函数(3)——DRAWICON、DRAWTEXT、DRAWNUMBER
  18. Java项目之画图板(一)
  19. 修复Visual Studio 2022 提示未能写入输出文件“*”,未能找到路径“*”的一部分错误
  20. 阴沟翻船——MHA测试主从失败NOT OK!

热门文章

  1. VS2005编译器选项
  2. 把一个用阿拉伯数字表示的正整数转换成汉字大写表示
  3. excel数据透视表_Excel数据透视表排序问题
  4. 配置zabbix管理账号
  5. 百度地图路线规划(途经点)
  6. 江南春:30年,我用1000亿,换来这99句话
  7. java 深入剖析ThreadLocal
  8. App 用户新体验——Agora Native SDK 3.4.0
  9. c语言结构体嵌套及输出,C语言结构体嵌套
  10. 阿里云域名申请 + 七牛云CDN加速