Linux内存管理--slab及其代码解析(1)(2)
一、slab相关数据结构
1)slab高速缓存描述符
- struct kmem_cache {
- struct array_cache *array[NR_CPUS];//为了提高效率,每个cpu都有一个slab空闲对象缓存
- /* 2) Cache tunables. Protected by cache_chain_mutex */
- unsigned int batchcount;//从本地高速缓存批量移入或移出对象的数目
- unsigned int limit;//本地高速缓存空闲对象的最大数目
- unsigned int shared;
- unsigned int buffer_size;
- struct kmem_list3 *nodelists[MAX_NUMNODES];//slab高速缓存空闲,部分空闲,无空闲slab的三个链表
- unsigned int flags; /* constant flags */
- unsigned int num;//每个slab obj的个数
- unsigned int gfporder;//每个slab中连续页框的数目
- gfp_t gfpflags;//分配页框时,传递给伙伴系统的标志
- size_t colour;//slab使用的颜色个数
- unsigned int colour_off; //slab的颜色偏移
- struct kmem_cache *slabp_cache; //指向存放slab描述符的chache,内部slab此字段为null
- unsigned int slab_size;//单个slab的大小
- unsigned int dflags; /* dynamic flags */
- //对象创建的构建函数
- void (*ctor) (void *, struct kmem_cache *, unsigned long);
- //对象的析构函数
- void (*dtor) (void *, struct kmem_cache *, unsigned long);
- const char *name;//slab高速缓存的名称
- struct list_head next;//通过该字段,将该cachep链接到cachep链表上
- }
2)slab描述符
- struct slab {
- struct list_head list; //将slab链接到各个slab链表上面,slabs_full, slabs_paril, slabs_free
- unsigned long colouroff;//slab中第一个对象的偏移
- void *s_mem; //slab中第一个对象的地址
- unsigned int inuse; //有多少对象正在被使用
- kmem_bufctl_t free; //表明接下来使用哪个空闲对象
- unsigned short nodeid;//该slab属于哪个内存节点
- }
slab描述符可能会被存放在两个地方:
外部slab描述符:存放在slab外部,位于cache_size指向的一个普通高速缓存中。
内部slab描述符:存放在slab的内部,位于分配给slab的内存的第一个页框的起始位置。
3)slab队列描述符
- struct kmem_list3 {
- struct list_head slabs_partial; //对象被使用了一部分的slab描述符的链表
- struct list_head slabs_full;//对象都被占用了的slab描述符的链表
- struct list_head slabs_free;//只包含空闲对象的slab描述符的链表
- unsigned long free_objects;//高速缓存中空闲对象的个数
- unsigned int free_limit;
- unsigned int colour_next; /* Per-node cache coloring */
- spinlock_t list_lock;
- struct array_cache *shared; //指向所有cpu所共享的一个本地高速缓存
- struct array_cache **alien; /* on other nodes */
- unsigned long next_reap; //由slab的页回收算法使用
- int free_touched; //由slab的页回收算法使用
- }
4)slab对象描述符
- typedef unsigned int kmem_bufctl_t;
每个对象都有一个类型为kmem_bufctl_t的对象描述符,每个slab描述符都有一个kmem_bufctl_t类型的数组来描述slab中的各个对象。其实该描述符记录的是下一个可用的空闲对象,使用了数组的索引来形成一个对象链表而已。对象描述符也分为内部对象描述符和外部对象描述符两种:
slab描述符和slab对象之间的组织图如下图所示:
二、slab的本地对象缓存
Linux2.6为了更好的支持多处理器,减少自旋锁的竞争并更好的利用硬件高速缓存,slab分配器的每个高速缓存都包含一个被称为slab本地高速缓存的每cpu数据结构,该结构由一个指向被释放对象的指针数组组成。这样的话,slab对象的释放和分配就只影响到本地的指针数组,减少了并发性。只有本地数组上溢或者下溢时才会去涉及slab结构。相关数据结构如下:
- struct array_cache {
- unsigned int avail;//本地高速缓存中可用对象的个数,也是空闲数组位置的索引
- unsigned int limit;//本地高速缓存的大小
- unsigned int batchcount;//本地高速缓存填充或者清空时使用到的对象个数
- unsigned int touched;//如果本地高速缓存最近被使用过,置成1
- spinlock_t lock;
- void *entry[0];
- }
同时在多cpu的环境下,还存在着一个共享高速缓存,它的地址被存放在高速缓存描述符的lists.shared字段中,本地共享高速缓存被所有cpu所共享,使得对象从一个本地高速缓存移至另一个高速缓存变的简单。
三、slab内存着色
比如cache line 32 字节,字节0-31一次从内存写入/读取,字节32-63一次从内存写入/读取…..
另外cache对应到内存位置不是任意的
Cache 地址0 对应到 内存地址0 , 32 ,64 ….
Cache 地址1 对应到 内存地址1 , 33 ,65 ….
…
一个slab大小肯定是整数页,所以起始地址末12位为零, 即都于cache0 对应。然后2个slab的每一个obj大小一样, 所以2个slab每个obj都对应相同的cache line.这样2个位置相同的obj都要频繁访问,比较容易使cache来回刷新,效率降低。
着色就是在第二个slab的起始位置空一个cache line出来,这样2个slab每个obj对应的cache错开一个,这样2个位置相同的obj即使频繁访问,也不会用一个相同cache line。
但是这种方法也是有限的,2个slab里面的obj对象的访问比较随即,不能保证哪两个在一个cache line 里。
评论暂时关闭