[linux kernel]slub内存管理分析(0) 导读
![[linux kernel]slub内存管理分析(0) 导读](http://pic.ttrar.cn/nice/%5blinuxkerne.jpg)
文章目录
-
- 简介
- 整体目录
- SLUB中的结构体关系图
- kmalloc 申请逻辑
-
- 逻辑图
- 逻辑简述
- kfree 释放逻辑
-
- 逻辑图
- 逻辑简述
- slab page状态转换关系图
简介
linux 内核内存管理算法有管理页面分配的伙伴算法,和对于小块内存的slab、slob、slub算法。其中slab是slob和slub的基础,slob多用于嵌入式设备中,目前linux内核中用到的内存管理算法是slub。本次分为下面几个章节从源码出发分析slub算法。我用的源码不是最新的是linux-5.13版本,主要是最开始看的时候用的这个版本,注释都写在这里,写博客的时候懒得换最新的了,可能有一些错误,欢迎指正。
整体目录
本系列文章从slub算法的结构体分析起,包括初始化、kmalloc申请操作、kfree释放操作和最后的销毁操作以及一些其他相关知识。
[linux kernel]slub内存管理分析(0) 导读
[linux kernel]slub内存管理分析(1) 结构体
[linux kernel]slub内存管理分析(2) 初始化
[linux kernel]slub内存管理分析(2.5) slab重用
[linux kernel]slub内存管理分析(3) kmalloc
[linux kernel]slub内存管理分析(4) 细节操作以及安全加固
[linux kernel]slub内存管理分析(5) kfree
[linux kernel]slub内存管理分析(6) 销毁slab
[linux kernel]slub内存管理分析(7) MEMCG的影响与绕过
SLUB中的结构体关系图
slub 算法中涉及的结构体不多,总共只有:
struct kmem_cachestruct kmem_cache_cpustruct kmem_cache_nodestruct page
他们之间的关系如下图:

kmalloc 申请逻辑
逻辑图

逻辑简述
其实slab 就是几级缓存机制,从cpu_slab 分配最快,能从cpu_slab当前freelist 分配就从cpu_slab当前freelist 分配,不能则从partial 列表中把一个slab page拿出来放到freelist,如果还没有就从node 里找slab page,都没有再新申请slab page。
- 首先判断请求
kmalloc分配内存的大小,大于slab可以分配的上限(通常8k)则调用kmalloc_large进行分配。kmalloc_large则直接根据大小调用伙伴系统分配适当的页数。
- 其他大小可以使用slab申请,则根据申请
flag和申请大小计算出kmalloc_caches的类型和index,获取对应的slab管理结构体。- 如果
flag存在ACCOUNT相关可能要切换到计数后slab,即kmalloc-cg相关slab(slab_pre_alloc_hook) - 获得slab 之后获取当前cpu 的
cpu_slab,如果当前cpu_slab的freelist不为空,则直接将freelist的第一个分配返回,然后freelist向后移动,更新tid等。 - 如果
cpu_slab的freelist为空,则看cpu_slab的partial链表是否为空,不为空则将partial链表第一个slab page 切换给cpu_slabfreelist,然后分配,partial指向下一个slab page。 - 如果以上都失败,说明
cpu_slab无法完成分配,需要新slab,则会找到合适当前运行cpu 的内存node所属kmem_cache_node结构,查询partial链表是否有可用slab page有的话将这个slab page给cpu_slab,然后也从这个node取出一些slab page补充到cpu_slab->partial,然后从freelist分配一个,跟上面一样。 - 如果还是没有,则调用
new_slab申请一个全新slab page,从新slab page的freelist分配。
- 如果
kfree 释放逻辑
逻辑图

逻辑简述
内存对象释放主要思路就是,如果是页面对象,则直接伙伴系统释放,如果是slab 对象,如果在cpu_slab中,在cpu_slab中释放,如果不是,则根据释放之前之后的状态(为空、为满、半满),进行不同的操作。
-
首先找到释放的内存对象所在的page 的page结构体。如果该page不是slab,也就是说内存对象不是通过slab分配的,而是直接分配的页(大块内存),那么直接释放页。
- 大块内存分配的时候就是从伙伴系统直接分配的页,释放的时候页通过伙伴系统释放页面(
__free_pages)
- 大块内存分配的时候就是从伙伴系统直接分配的页,释放的时候页通过伙伴系统释放页面(
-
其他内存是通过slab分配,则通过slab释放(
slab_free)-
memcg相关处理(
memcg_slab_free_hook) -
获取当前
cpu_slab,如果要释放的内存对象正好属于当前cpu_slab(可以理解为是否是从当前cpu_slab分配的),则快速释放- 获取
cpu_slab的freelist,将该内存对象插入freelist头部,刷新cpu_slab相关信息(do_slab_free)
- 获取
-
如果要释放的内存对象不属于当前
cpu_slab,(当前slab page在cpu_slab->partial、别的cpu_slab->page、别的cpu_slab->partial、游离状态、node->partial、node->full6种情况),需要慢速释放(__slab_free)- 先把内存对象释放到slab page的
freelist头部,更新slab page相关统计信息 - 如果该slab page为冻结状态(说明是在
cpu_slab中的三种情况)- 则直接结束(已经将
object放到page->freelist了,剩下的就不用管了)
- 则直接结束(已经将
- 如果释放前该slab page是满的(freelist为空),则说明
page目前是游离状态(不在任何列表中)或node->full中- 如果开启
cpu->partial,则将该slab page放到cpu_slab->partial中(从node->full中移除)- 如果
cpu_slab->partial满了,则要将当前cpu_slab->partial中的所有slab page放到node->partial中,然后再将新的slab page放到cpu_slab->partial中
- 如果
- 否则放入
node->partial中(从node->full中移除)
- 如果开启
- 如果释放后为空,则说明目前该slab page一定处在
node->partial列表中,因为如果在cpu_slab或者游离状态或node->full中不管释放完是否为空,都会在上面的步骤中处理完毕- 如果当前slab 管理的
partial页面数量满足最小要求,则将该释放后为空的slab page释放掉(__free_pages) - 否则不变,继续呆在
node->partial中
- 如果当前slab 管理的
- 否则说明该
page是本来就呆在node->partial中的半满page,并且释放后还是半满,则什么也不操作。
- 先把内存对象释放到slab page的
-
slab page状态转换关系图
结合kmalloc和kfree的逻辑,可以画出slab page的状态转换关系图:



