文章目录

  • 伙伴算法
    • **1、伙伴算法原理**
    • **2、物理页的分配**
    • **3、 物理页的释放 **
    • **总结**
  • Slab分配机制
    • **1、Slab如何对内存进行管理?**
    • **2、Slab中如何实现对页进行更细的划分?**
    • **3、Slab如何对内存进行分配**
    • 4、Slab如何对数据结构slab进行管理
    • 5、什么是kmem_cache?
  • 6、什么是slab对象?(Slab中用slab对象来代表内存块)
  • 7、slab着色
    • 总结
  • Slab与Slub的区别
    • Slab的缺点

伙伴算法

Linux采用著名的伙伴算法来解决外碎片的问题

1、伙伴算法原理

Linux的伙伴算法把所有的空间页面分为10个块组,每个组中块的大小是2的幂次方个页面,比如第0组中块的额大小为2的次方(1个页面),第1组中块的大小为2的1次方(2个页面)…,第9组中块的大小为2的9次方(512个页面),每一组中块的大小是相同的,且同样大小的块形成一个链表

2、物理页的分配

情景模拟:如果此时我们需要申请一块128个页面大小的内存,根据伙伴算法的规则,会先去128个页大小的块所构成的链表中寻找,如果存在空闲的块,那就把把这个块进行分配。 如果发现这个链表已经没有空闲的块了,那接着就去256个页大小的块所构成的链表中寻找,如果找到了空闲的块,那么将这个块分为2个128页大小的块,一个用来分配使用,另一个挂载到到128个页大小的块所构成的链表中去。如果还是没有,那接着就去512个页大小的块所构成的链表中寻找,如果找到了空闲的块,那么将其分为2个128页块,1个256页块。一个128的页块用来分配和使用,剩下的分别挂载到128的页块链表和256的页块链表下去…,当然如果这样一级一级的找下去,没有得到可以使用的空闲块,算法就放弃并发出错误信息

**3、 物理页的释放 **

满足如下条件的块称之为伙伴

(1) 两个块的大小相同

(2) 两个块的物理地址连续

伙伴算法把满足上述两个条件的块合并成一个块,该算法是迭代算法,如果合并后块还可以跟相邻的块进行合并,那此就继续合并

情景模拟:假设要释放一个256个页框的块,算法就把其插入到256个页框的链表中,然后检查与该内存相邻的内存,如果存在同样大小为256个页框的并且空闲的内存,就将这两块内存合并成512个页框,然后插入到512个页框的链表中,如果不存在,就没有后面的合并操作。然后再进一步检查,如果合并后的512个页框的内存存在大小为512个页框的相邻且空闲的内存,则将两者合并,然后插入到1024个页框的链表中。

总结

假设系统中有 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所示。

Slab分配机制

...有了伙伴系统 buddy,我们可以以页为单位获取连续的物理内存了,即 4K 为单位的获取,但如果需要频繁的获取/释放并不大的连续物理内存怎么办,如几十字节几百字节的获取/释放,这样的话用 buddy 就不太合适了因为这样会造成极大的内存浪费,这就引出了 slab,SLAB分配器实际上是建立在伙伴系统算法之上的,SLAB分配器使用的内存空间是通过伙伴算法进行分配的,只不过SLAB对这些内存空间实现了自己的算法进而对小块内存进行管理。
   场景模拟: 比如我需要一个 100 字节的连续物理内存,那么内核 slab 分配器会给我提供一个相应大小的连续物理内存单元,为 128 字节大小(不会是整好 100 字节,而是这个档的一个对齐值,如 100 字节对应 128 字节, 30 字节对应 32 字节, 60 字节对应 64 字节),这个物理内存实际上还是从伙伴系统获取的物理页;当我不再需要这个内存时应该释放它,释放它并非把它归还给伙伴系统,而是归还给 slab 分配器,这样等再需要获取时无需再从伙伴系统申请,这也就是为什么 slab 分配器往往会把最近释放的内存(即所谓“热” )分配给申请者,这样效率是比较高的。

1、Slab如何对内存进行管理?

我们可以将Slab管理机制分为三个部分:内核对象(object);高速缓存(cache);每个 slab 由一个或多个物理连续的页面组成(slab中对页进行更细的划分),每个 cache 由一个或多个 slab 组成,每个内核数据结构都有一个 cache。如下图所示

2、Slab中如何实现对页进行更细的划分?

以4k页为例,slab该内存页分组管理,每个组分别包含23、24、…2^11个字节(B),在4K页大小的默认情况下,另外还有两个特殊的组,分别是96b和192b个位,共11组。如下图所示:

3、Slab如何对内存进行分配

上面我们可以看到,我们将一个 页分成11个块,每个块的大小都不一样,如何对这些块(obj)进行管理, 这里引入一个概念,Slab分配的最小单位是obj,也就是上图中所示。我们将大小相同的obj,连接成一条链表。用数据结构slab进行管理,

4、Slab如何对数据结构slab进行管理

如下图所示,通俗点来讲,在我们通过struct kmem_list3 将所以的slab组织起来,根据obj部分分配,全部分配,全部未分配的特性,将所有的slab组织成三条链表

相关的数据结构

5、什么是kmem_cache?

...如上图所示,在结构体kmem_cache中我们重点关注,struct kmem_list3 和 struct array_cache这两个结构体成员,struct kmem_list3 我们已经知道是干啥了的。那struct array_cache的作用是啥,通俗点来讲,struct array_cache维护的是一个包含obj链表的slab结构体,申请内存时,我们会先到struct array_cache中寻址合适的obj块,如果没找到,在去struct kmem_list3找(先从obj部分分配的slab链表中找,没找到,再去全部未分配的slab链表找),找到后,将相应的slab挂载到struct array_cache中

6、什么是slab对象?(Slab中用slab对象来代表内存块)

7、slab着色

**CPU访问内存时使用哪个cache line是通过低地址的若干位确定的,比如cache line大小为32,那么是从bit5开始的若干位。因此相距很远的内存地址,如果这些位的地址相同,还是会被映射到同一个cache line。Slab cache中存放的是相同大小的对象,如果没有着色区,那么同一个cache内,不同slab中具有相同slab内部偏移的对象,其低地址的若干位是相同的,映射到同一个cache line。如图所示。
**

如此一来,访问cache line冲突的对象时,就会出现cache miss,不停的在cache line和内存之间来回切换,与此同时,其他的cache line可能无所事事,严重影响了cache的效率。解决这一问题的方法是通过着色区使对象的slab内偏移各不相同,从而避免cache line冲突。
着色貌似很好的解决了问题,实质不然,当slab数目不多时,着色工作的很好,当slab数目很多时,着色发生了循环,仍然存在cache line冲突的问题。

总结

...整个Slab系统中共有12个零售商(kmem_cache),每个“零售商”只“零售”特定大小的内存,例如:有的“零售商”只"零售"8Byte大小的内存,有的只”零售“16Byte大小的内存。
   每个零售商(kmem_cache)有两个“部门”,一个是“仓库”:struct kmem_list3,一个“营业厅”:struct array_cache。“营业厅”里只保留一个slab,只有在营业厅(kmem_cache_cpu)中没有空闲内存的情况下才会从仓库中换出其他的slab。
    所谓slab就是零售商(kmem_cache)批发的连续的整页内存,零售商把这些整页的内存分成许多小内存,然后分别“零售”出去,一个slab可能包含多个连续的内存页。slab的大小和零售商有关。(借鉴博客(24条消息) linux 内核 内存管理 slub算法 (一) 原理_lukuen的博客-CSDN博客_linux 内存管理算法)

Slab与Slub的区别

从版本 2.6.24 开始,SLUB 分配器取代 SLAB,成为 Linux 内核的默认分配器。SLUB 通过减少 SLAB 分配器所需的大量开销,来解决 slab 分配的性能问题,一个改变是,在 SLAB 分配下每个 slab 存储的元数据,移到 Linux 内核用于每个页面的结构 page。此外,对于 SLAB 分配器,每个 CPU 都有队列以维护每个 cache 内的对象,SLUB 会删除这些队列。对于具有大量处理器的系统,分配给这些队列的内存量是很重要的。因此,随着系统处理器数量的增加,SLUB 性能也更好。

Slab的缺点

1、 缓存队列管理复杂;

2、管理数据存储开销大;

3、对NUMA支持复杂;

4、 调试调优困难;

5、摒弃了效果不太明显的slab着色机制;

... 针对这些SLAB不足,内核开发人员Christoph Lameter在Linux内核2.6.22版本中引入一种新的解决方案:SLUB分配器。SLUB分配器特点是简化设计理念,同时保留SLAB分配器的基本思想:每个缓冲区由多个小的slab 组成,每个 slab 包含固定数目的对象。SLUB分配器简化kmem_cache,slab等相关的管理数据结构,摒弃了SLAB 分配器中众多的队列概念,并针对多处理器、NUMA系统进行优化,从而提高了性能和可扩展性并降低了内存的浪费。为了保证内核其它模块能够无缝迁移到SLUB分配器,SLUB还保留了原有SLAB分配器所有的接口API函数。
  总结: 相对Slab来说,Slub的内存分配思想其实差不太多,其实就是Slab的优化版

参考文献(本次的一些图片来源于以下文章,如有侵权,联系删除)

Linux伙伴算法 - AlanTu - 博客园 (cnblogs.com)

linux 内核 内存管理 slub算法 (一) 原理_lukuen的博客-CSDN博客_linux 内存管理算法

Linux内存管理之SLAB原理浅析。_阿曼的博客-CSDN博客_linux slab

linux内核之slob、slab、slub_rtoax的博客-CSDN博客

linux内核之slob、slab、slub_rtoax的博客-CSDN博客

Linux内存管理之slab机制(概述)

剖析linux的内存管理与分配相关推荐

  1. 详细剖析linux的内存管理方式(分段式、分页式、段页式),以及进程状态的具体关系

    进程状态之间的关系: 1.分段式内存管理: 分段:进程地址空间按照逻辑关系将自身划分为若干个段,每个段都有自己的段名,从0开始编址. 内存分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各 ...

  2. linux按进程分配物理内存,linux下内存管理学习心得(一)

    最近在学习内存管理的时候,发现对linux下的所谓内存如何管理如何分配都不熟悉,通过最近的查阅资料可总结如下,如有不妥之处欢迎大家批评与指正. 总的的来说linux的内存管理其实主要难理解的是以下几个 ...

  3. 【Linux 内核 内存管理】内存管理架构 ④ ( 内存分配系统调用过程 | 用户层 malloc free | 系统调用层 brk mmap | 内核层 kmalloc | 内存管理流程 )

    文章目录 一.内存分配系统调用过程 ( 用户层 | 系统调用 | 内核层 ) 二.内存管理流程 一.内存分配系统调用过程 ( 用户层 | 系统调用 | 内核层 ) " 堆内存 " ...

  4. 【Linux 内核 内存管理】分区伙伴分配器 ② ( free_area 空闲区域结构体源码 | 分配标志位 | GFP_ZONE_TABLE 标志位区域类型映射表 |分配标志位对应的内存区域类型 )

    文章目录 一.free_area 空闲区域结构体源码分析 二.分配标志位 三.GFP_ZONE_TABLE 标志位区域类型映射表 四.分配标志位对应的内存区域类型 一.free_area 空闲区域结构 ...

  5. 【Linux 内核 内存管理】物理分配页 ⑨ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | retry 标号代码分析 )

    文章目录 一.retry 标号代码分析 二.retry 标号完整代码 在 [Linux 内核 内存管理]物理分配页 ② ( __alloc_pages_nodemask 函数参数分析 | __allo ...

  6. 【Linux 内核 内存管理】物理分配页 ⑦ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | 判断页阶数 | 读取 mems_allowed | 分配标志位转换 )

    文章目录 一.__alloc_pages_slowpath 慢速路径调用函数 二.判断页阶数 三.读取进程 mems_allowed 成员 四.分配标志位转换 五.__alloc_pages_slow ...

  7. 【Linux 内核 内存管理】物理分配页 ⑧ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | 获取首选内存区域 | 异步回收内存页 | 最低水线也分配 | 直接分配 )

    文章目录 一.获取首选内存区域 二.异步回收内存页 三.最低水线也分配 四.直接分配内存 在 [Linux 内核 内存管理]物理分配页 ② ( __alloc_pages_nodemask 函数参数分 ...

  8. Linux glibc内存管理:用户态内存分配器——ptmalloc实现原理

    文章目录 ptmalloc 设计假设 Arena Chunk Bins 内存分配.释放流程 总结 C++ STL : SGI-STL空间配置器源码剖析 Linux 内存管理 | 物理内存管理:物理内存 ...

  9. Linux堆内存管理深入分析(上)

    Linux堆内存管理深入分析 (上半部) 作者:走位@阿里聚安全   0 前言 近年来,漏洞挖掘越来越火,各种漏洞挖掘.利用的分析文章层出不穷.从大方向来看,主要有基于栈溢出的漏洞利用和基于堆溢出的漏 ...

最新文章

  1. Git统计个人提交代码行数
  2. jQuery日期和时间插件(jquery-ui-timepicker-addon.js)中文破解版使用
  3. Mysql里的日期类型 和JPA里@Temporal
  4. 转 C# 串口编程遇到的问题以及解决方法
  5. android 调用红外模块,Flutter调用Android模块的功能
  6. P3978 [TJOI2015]概率论(生成函数)
  7. vue设置页面标题title
  8. 可达性统计(拓扑排序)
  9. Excel 修改 【数据图表】 的 【数据源】 的范围 (VBA)
  10. java后端做教育视频网站源码_基于 Java Spring cloud的开源在线教育系统调试实战...
  11. Libxml2的简单介绍及应用
  12. 解读《美国国家BIM标准》— BIM能力成熟度模型(八)
  13. 一台计算机连接两个投影,Win10系统电脑外接双显示器(投影仪)设置图文教程
  14. python弹球游戏添加一个球_Python实现的弹球小游戏示例
  15. ArcGIS教程:太阳辐射建模
  16. 【Comsol学习】二维非稳态热传导问题
  17. 商品货架管理(愿疫情早日消散,大家去见想见的人)
  18. Servlet | ServletConfig接口、ServletContext接口详解
  19. ES(ElasticSearch) 如何建立索引
  20. 什么值传递和引用传递

热门文章

  1. 抓取豆瓣的电影排行榜TOP100
  2. 利用selenium模拟自动登录链家、贝壳、安居客等网站(超级实用,推荐收藏!)
  3. linux系统端口扫描工具,[命令] Linux 端口扫描工具 nmap 的使用(转载)
  4. 【进程控制(进程退出、孤儿进程、僵尸进程)_Linux】
  5. Verilog 中需要使用原语的情况
  6. 来自“啄木鸟社区”的奋起宣言
  7. 华为手机怎么找回计算机功能,华为手机怎么在电脑上显示
  8. 微信小程序this.setData()
  9. CSS-CSS2选择器
  10. 使用Python汇总APAI64硬件报告信息汇总硬件台账