Linux内存管理-slub算法
-
Slub 简介
Linux 内核内存管理用了两个算法:伙伴算法(以页为单位的大内存)和 slub 算法(以字节为单位的小内存),其中 slub 系统运行在伙伴系统之上。
slub 进行内存分组管理,分别设置 2^3 ~ 2^11 字节和 96B、192B 共 11 个组,
在内核中的控制结构为 kmalloc_caches[12],
struct kmem_cache kmalloc_caches[PAGE_SHIFT] __cacheline_aligned;
每个数组元素(kmem_cache)对应一种大小的内存,kmem_cache 的主要结构有 kmem_cache_cpu 和 kmem_cache_cpu。在 kmem_cache_cpu 中只存一个 slab(连续的整页内存),只有在 kmem_cache_cpu 中没有空闲内存的情况下才会从 kmem_cache_node 中换出其它的 slab。
-
申请结构
物理页按照 object 大小组成链表,每个 object 包含指向下一个 object 的指针(void*),当 slub 系统申请内存块的时候,会把内存块当 object 看待。
-
申请内存
case1: slub 系统初始化,也就是第一次申请
当前 kmem_cache_cpu 和 kmem_cache_node 中没有可用的 slab,因此只能向伙伴系统申请空闲内存页,并将其分为多个 object,然后取出其中的一个 object 并标记为已被占用,接着返回给用户。
其余的 object 会标记为空闲并放在 kmem_cache_cpu 中保存,kmem_cache_cpu 中的 freelist 保存着下一个空闲 object 的地址。
case2: kmem_cache_cpu 中保存的 slab 上有空闲的 object 可用
直接把 kmem_cache_cpu 中的下一个空闲 object 返回给用户,并把 freelist 指向下一个空闲的 object。
case3: kmem_cache_cpu 中没用空闲但 kmem_cache_node 中有空闲
此时会从 kmem_cache_node 的 partial 变量中获取有空闲的 object 的 slab 并返回给用户。
同时还会对 kmem_cache 进行一些调整,其中 kmem_cache_node 中的 full 和 partial 分别存放了全满和不满的 slab。这时会从 partial 中挑一个不满的 slab 放到 kmem_cache_cpu 中,并把 kmem_cache_node 中满了的 slab 放到 full 中。
case4: kmem_cache_node 和 kmem_cache_cpu 中的 slab 已经都满了
这时只能向伙伴系统重新申请一个 slab。
-
释放内存
case1: kmem_cache_cpu 中缓存的 slab 就是该 object 所在的 slab
该 slab 还在 kmem_cache_cpu 中,把该 object 放到空闲列表中即可。
下面的情况都是该 slab 已经被放到了 kmem_cache_node 中。
case2: object 所在的 slab 是 full 状态
那么释放 object 之后,该 slab 就是 partail 状态,此时把该 slab 添加到 kmem_cache_node 中的 partial 链表中。
case3:slab 是 partial 状态
直接把该 object 加入到该 slab 的空闲队列中
case4: object 在释放后,slab 中的 object 全部是空闲的
此时还需要把整个 slab 释放掉。
-
参考文献