Memslab从结构上可以分为三层,
1最顶层是一些cache队列,
2 每个cache队列中又包含三个slab队列,
3 每个slab管理着一个页面
我们首先从这三层来介绍memslab的整体结构
1 cache队列
最顶层与cache相关的队列有
- Ikmem_array: 指向不同大小的cache
- Ikmem_lookup: 将cache按照从大到小的顺序排列组成的数组
- Ikmem_size_lookup1: 以4为间隔的大小(范围从4到1024),每个指向第一个大于自身大小的cache
- Ikmem_size_lookup2: 以1k为间隔的大小(范围从1k到256k),每个指向第一个大于自身大小的cache
- ikmem_large_ptr: 存放大于128k的页面
1.1 ikmem_array和ikmem_lookup数组
Memslab中用来存放cache结构的是ikmem_array数组和ikmem_lookup数组, 这两个数组被放在一块大小为2* sizelimit 大小的内存上, size_limit会随着ikmem_array的大小而变化,
在ikmem_init中,创建2^16, 2^15 … 2^3共14个cache,ikmem_array和ikmem_lookup都指向这些cache,只不过ikmem_lookup中cache是按照从大到小的顺序排列的
1.2 Ikmem_size_lookup1和Ikmem_size_lookup2数组
Ikmem_size_looup1: 以4为间隔的大小(范围从4到1024),每个指向第一个大于自身大小的cache
Ikmem_size_lookup2: 以1k为间隔的大小(范围从1k到256k),每个指向第一个大于自身大小的cache, 超过2^16的大小指向NULL
2 cache
Cache中比较重要的结构是imemlru_t array, array中会有一个entry放着刚刚被应用返回的slab中的对象,slab中的对象被返回后不会直接返回给slab,而是先放在这个数组中
以及三个slab的链表:slabs_partial, slabs_full, slabs_free, slabs_partial存放的slabs中的对象被部分分配出去,slabs_full中的对象被全部分配出去,slabs_free中的对象完全没有被分配出去
3 slab
每个slab管理着一个页面,按照obj_size将页面分为obj1, obj2 …,在未分配的时候每个对象的开头都指向下一个对象的地址,bufctl指向这个待分配链表的头部
分配算法,是一种使用单链表去管理页面空间的方式,每次分配头指针bufctl指向的页面,将bufctl指向下一个对象,对象被应用释放返回时,将对象加入链表头部,原理类似下图所示
主要的函数为ikmem_init, ikmem_malloc和ikmem_free,我们从malloc和free入手,去看一看其中的流程:
1 Ikmem_malloc:
分配时, 如果需要分配的大小小于1024, 首先在ikmem_size_lookup1中查找, 否则在ikmem_size_lookup2中寻找cache,
如果在ikmem_size_lookup1以及ikmem_size_lookup2中没有与size相同大小的cache, 就从ikmem_lookup中找到第一个比size大的cache
当所需要的size大于之前准备的2^16大小的页面, malloc一个页面, 并加入ikmem_large_ptr队列
如果在ikmem_size_lookup1或是在ikmem_size_lookup2中发现了需要的cache, 调用imemcache_alloc函数, 从这个cache中分配一个对象
1.1 Ikmem_malloc->imemcache_alloc:
程序会先去看该cache中的array有没有空余的对象, cache中的array存放着刚刚被从应用释放回来的页面, 刚释放回来的页面不会立刻放回其所属的slab, 而会放入array, 与其他刚被释放的页面形成链表, 这样的好处是避免了每次去slab中分配页面, 并且还要调整slab所属的队列,
如果array中缓存的对象为空, 就会调用imemcache_fill_batch, 从slab队列中分配batchcount个对象到array中, 然后返回这个对象
从cache中分配出去的对象的大小会被加到总的分配出去的大小ikmem_inuse上
2 ikmem_free:
首先判断, 如果分配的对象是一个在大页面的对象, 就从ikmem_large_ptr队列中删除这个对象, 并且free掉这个对象
否则的话, 调用imemcache_free去释放这个对象, 释放完后, 同样要从ikmem_inuse中减去这个释放回来的大小
2.2 Ikmem_free -> imemcache_free:
释放回来的页面会首先放到array中去,
如果array中的对象的数目超过了array->limit的大小, 程序会调用imemcache_list_free, 这个对象就会被放回slab中, 并且程序会调整slab所在的slab队列, 比如原先在slab_free中的slab, 由于对象被返回, 就会被调整到slab_partial中
如果cache中空闲的slab超过了一定数量(cache->free_limit), cache就会调用imemcache_drain_list, 去释放掉一半数量的空闲对象