Linux内存管理之slab分配器分析

一:准备知识:

前面我们分析过了大内存分配的实现机制,事实上, 若为小块内存而请求整个页面,这样对于内存来说是一种极度的浪费。因此linux 采用了slab 来管理小块内存的分配与释放。Slab 最早是由sun 的工程师提出。它的提出是基于以下因素考虑的:

1 :内核函数经常倾向于反复请求相同的数据类型。比如:创建进程时,会请求一块内存来存放mm 结构。

2 :不同的结构使用不同的分配方法可以提高效率。同样,如果进程在撤消的时候,内核不把mm 结构释放掉,而是存放到一个缓冲区里,以后若有请求mm 存储空间的行为就可以直接从缓冲区中取得,而不需重新分配内存.

3: 前面我们曾分析过,如果伙伴系统频繁分配,释放内存会影响系统的效率,以此,可以把要释放到的内存放到缓冲区中,直至超过一个阀值才把它释放至伙伴系统,这样可以在一定程度上缓减减伙伴系统的压力

4: 为了缓减“内碎片”的产生,通常可以把小内存块按照2 的倍数组织在一起,这一点和伙伴系统类似

二:slab 分配器概貌:

Slab 将缓存分为两种:一种是专用高速缓存,另外一种是普通高速缓存。请注意,这里所说的高速缓存和硬件没有必然的关系,它只是slab 分配器中的一个软件概念。


专用高速缓存中用来存放内核使用的数据结构,例如:mm,skb,vm 等等

普通高速缓存是指存放一般的数据,比如内核为指针分配一段内存

所有的高速缓存区都通过链表的方式组织在一起,它的首结点是cache_chain

另外,普通高速缓存将分配区分为32*(2^0),32*(2^1),32*(2^2) ….32*(2^12) 大小,共13 个区域大小,另外,每个大小均有两个高速缓存,一个为DMA 高速缓存,一个是常规高速缓存。它们都存放在一个名这cache_size 的表中.

Slab 分配器把每一个请求的内存称之为对象(和oop 设计方法中的对象类似,都有初始化与析构). 对象又存放在slab.slab 又按照空,末满,全满全部链接至高速缓存中. 如下图所示:

 

三:slab 分配器相关的数据结构:

高速缓存:

typedef struct kmem_cache_s kmem_cache_t;

struct kmem_cache_s {

struct array_cache *array[NR_CPUS];/*per cpu 结构,每次分配与释放的时候都先从这里取值与存值*/

unsigned int       batchcount;  /*array[NR_CPUS] 中没有空闲对象时,一次为数组所分配的对象数*/

unsigned int       limit;   /* array[NR_CPUS] 中所允许的最大空闲数 */

struct kmem_list3  lists;   /* 将在后面分析*/

unsigned int       objsize; /*slab 中的对象大小*/

     unsigned int      flags;   /* cache 标志*/

     unsigned int       num; /* 每个slab 中的对象数量 */

     unsigned int       free_limit; /* upper limit of objects in the lists */

     spinlock_t         spinlock;

     unsigned int       gfporder; /*2^gfporder 即为cacheslab 的大小*/

     unsigned int       gfpflags;

 

     size_t             colour;       /* 着色机制,后面会详细分析 */

     unsigned int       colour_off;   /* colour offset */

     unsigned int       colour_next;  /* cache colouring */

     kmem_cache_t       *slabp_cache;/*slab 描述符放在缓存区外面时,此值指向描述符在普通缓存区中的位置*/

     unsigned int       slab_size;  /* 每一个slab 的大小*/

     unsigned int       dflags;       /* dynamic flags */

     void (*ctor)(void *, kmem_cache_t *, unsigned long); /* 构造函数*/

     void (*dtor)(void *, kmem_cache_t *, unsigned long); /* 析构函数*/

     const char         *name; /*cache 的名字*/

     struct list_head   next; /* 下一个cache 用来构成链表*/

 

/* 5) statistics */

#if STATS

     unsigned long      num_active;

     unsigned long      num_allocations;

     unsigned long      high_mark;

     unsigned long      grown;

     unsigned long      reaped;

     unsigned long          errors;

     unsigned long      max_freeable;

     atomic_t      allochit;

     atomic_t      allocmiss;

     atomic_t      freehit;

     atomic_t      freemiss;

#endif

#if DEBUG

     int           dbghead;

     int           reallen;

#endif

}

这里值得注意的地方是,与2.4 相比,slab 部份的结构与成员位置发生了很大改变。一般来说经常用的成员放在结构体的前面。后面会解述为什么。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值