Slub内存分配器,是在slab的基础上,进一步优化而来,在内存管理,多处理并发访问上更有优势.
这里主要讲解slub分配,释放,调试选项,以及针对slab的优化,源代码基于3.18.22
slub是特定大小内存的集合(称为object),每个slub可以包含多个page,代码中用
struct kmem_cache, struct kmem_cache_node, struct kmem_cache_cpu来实现整个slub
关系如下:
struct kmem_cache {
struct kmem_cache_cpu __percpu *cpu_slab; /*per cpu数据,分配内存时,可以直接返回object */
unsigned long min_partial; /*每个cache 最小slab数量 */
int size; /* The size of an object including meta data */
int object_size; /* The size of an object without meta data */
int offset; /* Free pointer offset. */
int cpu_partial; /* Number of per cpu partial objects to keep around
如果大于这个值,然后就会释放slab到系统中 */
int inuse; /* Offset to metadata */
int align; /* Alignment */
const char *name; /* Name (only for display!) */
struct list_head list; /* List of slab caches */
struct kmem_cache_node *node[MAX_NUMNODES]; /*内存分配 */
};
struct kmem_cache_node {
spinlock_t list_lock; /*访问partial链表锁 */
#ifdef CONFIG_SLUB
unsigned long nr_partial; /*node上的slab数量 */
struct list_head partial; /*所有的slab挂接 */
#endif
};
struct kmem_cache_cpu {
void **freelist; /* Pointer to next available object */
unsigned long tid; /* Globally unique transaction id:全局标志,用户免锁机制实现 */
struct page *page; /* The freelist from which we are allocating */
struct page *partial; /* Partially allocated frozen slabs list :从node中分配的内存*/
};
为什么 kmem_cache_cpu和kmem_cache_node都会挂接内存? 这种做是基于什么目的了?
这种做能够提高内存分配效率,具体在分配一节分析.
slub内存分配有五种情况, 效率从高到低.
这里cpu指struct kmem_cache_cpu结构体 node指struct kmem_cache_node
前三种情况都是从percpu上直接分配内存
2. 1. cpu->freelist分配
这种效率最高, 免锁操作,且中断开启
2. cpu->page 分配
类似与第一个
cpu->freelist = cpu->page->freelist ;
cpu->page->freelist = NULL ;
3. cpu->partial list
percpu的partial 上挂接了多个slab
cpu->page = cpu->partial ;
cpu->freelist = cpu->page->freelist ;
cpu->page->freelist = NULL ;
cpu->partial = cpu->page->next ;
免锁操作,禁止本地中断
4. node->partial list
如果percpu都分配失败,那么从node上分配 ,这样需要拿spinlock list_lock
1. 获取node->partial第一个page
cpu->page = nodepage
cpu->freelist = nodepage->freelist
nodepage->freelist = NULL
2. 当cpu->partial 总的object小于kmemcache->cpu_partial时
获取node->partial list上的slab 挂接到cpu->partail 直到总的object大于cpu_partail
5. alloc page
当上面四种情况都分配失败时,向邻居系统申请page,也即调用page_alloc
内存释放分为三种情况
1. free to cput->freelist
2. free to cput->partial list
3. free to node->partial list
再释放object时,还设计到内存回收,也即释放内存到伙伴系统
当cpu partial 的objects > cpu_partial 时,
put page to node partial list
当node 上挂接的slab数据nr_partial 大于min_partial 且slab 全空时,
释放内存到伙伴系统
this_cpu_cmpxchg_double :避免禁止中断
cmpxchg_double :避免使用锁