内存管理---Slab原理分析

内存管理---Slab原理分析概念介绍 什么是 slab slab 是 slab 内存分配器从 buddy system 申请页面的基本单位 然而 slab 的大小不是固定的 slab 从属于某个 kmem cache 实例 不同的 kmem cache 实例 其 slab 的大小是不同的 slab 的大小必须是 2 order 个 pages order 不能超过 buddy

大家好,我是讯享网,很高兴认识大家。

概念介绍

什么是slab?

slab是slab内存分配器从buddy system申请页面的基本单位。然而slab的大小不是固定的,slab从属于某个kmem cache实例,不同的kmem cache实例,其slab的大小是不同的。slab的大小必须是2^order个pages,order不能超过buddy system所支持的最大的order。

slab内存分配器从buddy system分配了slab之后,会将其挂在对应的kmem cache实例的node节点。

什么是object?

object是slab内存分配器对外提供的申请内存的基本单位。slab内存分配器从buddy system申请了buddy之后,会将其拆分成一个个object,并缓存在kmem cache实例的cpu_cache中,用户申请内存时,其实获取的就是一个个object。

一旦object缓存耗尽,就会重新从buddy system申请slab,并将其拆分成object,放入内存池。

什么是cache?

slab内存分配器中的cache跟硬件cache无关,是一个纯软件的概念。slab内存分配器有两种cache,一个是slab的cache,一个是object的cache。slab内存分配器从buddy system获取页面后,会将其加入kmem cache的node节点,这个就是slab的cache;将slab拆分成多个object,并将object加入kmem cache的cpu_cache内存池,这个就是object的cache;可以看到这两种cache实际是对共同的物理页面的两种缓存形式。

原理分析

作用

slab是为了进行更细粒度的内存分配,满足小于一页的内存分配需求,将页拆分为更小的单位。
Linux中支持slab、slub、slob。 一般在使用kmalloc进行内存分配时就使用到了slab分配器。
Slab分配器和伙伴系统以及内核调用接口之间的关联如下:

在这里插入图片描述
讯享网

Slab组成:

Slab分为管理数据结构kmem_cache和保存各个object的各个slab,如下图所示:
在这里插入图片描述内核中所有的kmem_cache通过cache_chain连接起来。
内核初始化的时候首先创建了一个cache_cache的静态kmem_cache结构,内核后续创建新的kmem时候直接从这个cache_cache管理slab的obj中取出。

Struct kmem_cache:(以4.4.6内核为例)

struct kmem_cache { 
    unsigned int object_size;/* The original size of the object */ unsigned int size; /* The aligned/padded/added on size */ unsigned int align; /* Alignment as calculated */ unsigned long flags; /* Active flags on the slab */ const char *name; /* Slab name for sysfs */ int refcount; /* Use counter */ void (*ctor)(void *); /* Called on object slot creation */ struct list_head list; /* List of all slab caches on the system */ }; 

讯享网

struct kmem_list3 在4.x的内核中为kmem_cache_node:

讯享网struct kmem_cache_node { 
    spinlock_t list_lock; #ifdef CONFIG_SLAB struct list_head slabs_partial; /* partial list first, better asm code */ struct list_head slabs_full; struct list_head slabs_free; unsigned long free_objects; unsigned int free_limit; unsigned int colour_next; /* Per-node cache coloring */ struct array_cache *shared; /* shared per node */ struct alien_cache **alien; /* on other nodes */ unsigned long next_reap; /* updated without locking */ int free_touched; /* updated without locking */ #endif #ifdef CONFIG_SLUB unsigned long nr_partial; struct list_head partial; #ifdef CONFIG_SLUB_DEBUG atomic_long_t nr_slabs; atomic_long_t total_objects; struct list_head full; #endif #endif }; 

Struct array_cache:(内核为每个CPU都提供一个array_cache实例)

struct array_cache { 
    unsigned int avail; unsigned int limit; unsigned int batchcount; unsigned int touched; void *entry[]; /* * Must have this definition in here for the proper * alignment of array_cache. Also simplifies accessing * the entries. * * Entries should not be directly dereferenced as * entries belonging to slabs marked pfmemalloc will * have the lower bits set SLAB_OBJ_PFMEMALLOC */ }; 

这些数据结构间的关系:
在这里插入图片描述我们主要关心数据结构之间的连接关系,所以先看kmem_cache中的kmem_list3和array_cache这两个成员。
struct kmem_list3
kmem_list3是per node类型数据,一个node对应一个kmem_list3结构,我们的系统是UMA,所以只有一个kmem_list3结构。
kmem_list3中有三个链表slabs_partial、slabs_full、slabs_free,每个链表中挂着都是slab结构。其中,已经有部分obj被分配出去的slab均挂在slabs_partial下;全部obj都被分配出去的slab挂在slabs_full下;全部obj都未分配出去的slab挂在slabs_free下。
struct array_cache
array_cache是per cpu类型数据,每个core对应一个array_cache结构。
当array_cache中的obj为空时,系统会以batchcount值为准,一次性从kmem_list3中搬运batchcount个obj到arry_cache中,存放在entry里。
slab
slab主要包含两大部分,管理性数据和obj对象,其中管理性数据包括struct slab和kmem_bufctl_t。
slab有两种形式的结构,管理数据外挂式或内嵌式。如果obj比较小,那么struct slab和kmem_bufctl_t可以和obj分配在同一个物理page中,可称为内嵌式;如果obj比较大,那么管理性数据需要单独分配一块内存来存放,称之为外挂式。我们在上图中所画的slab结构为内嵌式。

Kmem_bufctl_t

管理性数据kmem_bufctl_t的类型是unsigned int,本质上是一个空闲obj链表,用于描述下一个可用obj序号。初始化时,当前slab中的obj均可用,所以图中kmem_bufctl_t中的值依次就是下一个可用的obj序。
kmem_bufctl_t中使用方法可参考下图场景。
在这里插入图片描述系统初始化时slab->free执行0#slab,某时刻系统已将0#—3# obj分配出去,此时slab->free指向4# slab,而4#slab对应的kmem_bufctl_t中存放的值是5。表明slab中current可用obj是4#,next可用obj是5#。
系统运行一段时间后,1# obj需回收。此时,1#obj对应的kmem_bufctl_t中填入slab->free值4,并将slab->free修正为1。这表明slab中current可用obj是1#,next可用的obj为4#。

SLAB分配流程以及管理逻辑

在这里插入图片描述obj分配优先考虑从array_cache的entry中取,取的规则遵循LIFO原则,先从enry的末尾取出obj,因为这个obj很有可能还在硬件cache中,是热的。如果entry为空,则说明是第一次从array_cache中分配obj或者是array_cache中的所有obj都已分配,所以需要先从kmem_cache的kmem_list3中取出batchcount个obj,把这些obj全部填充到enty中,然后再分配。
obj释放也是优先考虑释放到array_cache中,而不是直接释放到kmem_list3中。只有array_cache中的obj超过了limit上限,系统才会将enty中的头batchcount个obj搬到kmem_cache所在的kmem_list3中,然后将entry中剩余obj向前移动,然后再将准备释放的obj放到entry的末尾。

小讯
上一篇 2025-03-31 15:01
下一篇 2025-03-10 21:28

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/71024.html