1.slab分配器是如何分配和释放小内存块的?
1.1分配函数kmem_cache_alloc
1.1.1从对象缓冲池获取分配对象
使用cpu_cache_get()来获取slab描述符cachep中的本地对象缓冲池ac,如果ac中没有空闲的分配对象,则直接通过ac_get_obj来分配一个对象。
1.1.2实际分配函数cache_alloc_refill()
首先去判断共享对象缓冲池有没有空闲对象,如果有,就尝试迁移batchcount个空闲对象到本地对象缓冲池ac中;如果没有,就会去查看slab节点中的slabs_partial链表(部分空闲链表)和slabs_free链表(全部空闲链表);如果都没有,说明整个slab节点都没有空闲对象,这时候就需要重新分配slab节点。
分配slab节点函数:cache_grow。
增加slab描述符的colour_next,每个slab加1,直到这个slab描述符的colour最大值,然后又从0开始增加。Colour的大小是cache line的大小,有利于提高硬件cache效率。
kmem_getpages分配一个slab所需的页面,2^gfporder个页面。alloc_slabmgmt()计算cache colour和freelist,以及对象的地址布局。page->freelist是内存块起始地址减去cache colour后的地址,page->s_mem是slab中第一个对象的起始地址,内存块起始地址减去cache colour和freelist_size。
cache_grow初始化完所有的slab对象状态后,将这个slab添加到slabs_free链表中。
1.2释放函数kmem_cache_free()
通过要释放对象的虚拟地址找到对应的kmem_cache数据结构。由对象的虚拟地址通过virt_to_pfn找到相应的pfn,然后通过pfn_to_page由pfn找到对应的page结构。
如果slab的共享对象缓冲池中空闲对象数量大于limit阈值,就会触发free_block函数释放batchcount个空闲对象;如果本地对象缓冲池中的空闲对象数量大于limit阈值,就会触发cache_flusharray函数去做flush动作尝试回收空闲对象;如果slab中没有活跃的对象,就会调用destroy函数来销毁这个slab。
2.slab分配器中有一个着色的概念,着色有什么用?
cache colour着色区让每一个slab对应大小不同的cache行,着色区大小的计算colour_next*colour_off,前者为slab描述符计算出的colour最大值,后者为L1 cache的cache行大小。这样可以使得不同slab上同一个相对位置slab对象的起始地址在高速缓存上相互错开,有利于改善高速缓存的效率。
3.slab分配器中的slab对象有没有根据per-cpu做优化?
slab分配器有针对per-cpu进行优化,分配器中有per-cpu类型的本地对象缓冲池,有两个好处:①让一个对象尽可能的运行在一个cpu上,使用同一个cpu的cache,有利于提高性能;②访问per-cpu类型的本地缓冲池不需要获取自旋锁,因为不会有其他cpu来访问,避免了自旋锁的竞争。
4.slab增长并导致大量不可用的空闲对象,该如何解决
有两种回收内存的方式:①kmem_cache_free释放②slab中有个定时器,定时扫描slab描述符,收受一部分空闲的对象。参考cache_reap()。