一、概序
linux内存管理的基础是:伙伴系统(buddy system),但伙伴系统是以页为单位(4kB)管理和分配内存。现实
的需求是以字节为单位,这样基于Buddy系统分配最小的一个page会严重的浪费内存。slab分配器就是为了解决此问
题而出现,专为小内存分配而生。slab分配器分配内存以Byte为单位。但是slab分配器是基于伙伴系统分配的大内存
进一步细分成小内存分配,是在buddy系统上封装了一层算法实现此功能,后面会介绍slab分配的原理及方法。
另外当前都使用的SLUB分配器,SLUB分配器是基于SLAB分配做的优化,使得可以快速地进行对象的分配和回
收并减少内存碎片,发明SLUB分配器的主要目的就是减少slab缓冲区的个数,让更多的空闲内存得到使用。
二、相关结构体
slub分配器来说,就是将这段连续内存平均分成若干大小相等的object(对象)进行管理。 slub把内存分组管理,
每个组分别包含2^3、2^4、...2^11个字节,每个分组使用一个struct kmem_cache的结构体来描叙。
/*
* Slab cache management.
*/
struct kmem_cache {
struct kmem_cache_cpu __percpu *cpu_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. */
struct list_head list; /* List of slab caches */
struct kmem_cache_node *node[MAX_NUMNODES];
};
/*
* The slab lists for all objects.
*/
struct kmem_cache_node {
spinlock_t list_lock;
#ifdef CONFIG_SLUB
unsigned long nr_partial;
struct list_head partial;
#ifdef CONFIG_SLUB_DEBUG
atomic_long_t nr_slabs;
atomic_long_t total_objects;
struct list_head full;
#endif
#endif
};
struct kmem_cache_cpu {
void **freelist; /* Pointer to next available object */
unsigned long tid; /* Globally unique transaction id */
struct page *page; /* The slab from which we are allocating */
struct page *partial; /* Partially allocated frozen slabs */
#ifdef CONFIG_SLUB_STATS
unsigned stat[NR_SLUB_STAT_ITEMS];
#endif
};
struct kmem_cache *kmalloc_caches[12];
关于上面三个链表的关系通俗的理解可以参考文章slub算法,每个数组kmalloc_caches元素对应一种大小的内存,
可以把一个kmem_cache结构体看做是一个特定大小内存的零售商,整个slub系统中共有12个这样的零售商,每个
“零售商”只“零售”特定大小的内存,例如:有的“零售商”只"零售"8Byte大小的内存,有的只”零售“16Byte大小的内存。
每个零售商(kmem_cache)有两个“部门”,一个是“仓库”:kmem_cache_node,一个“营业厅”:kmem_cache_cpu。
“营业厅”里只保留一个slab,只有在营业厅(kmem_cache_cpu)中没有空闲内存的情况下才会从仓库中换出其他的slab。
三、SLUB分配及释放接口
1、创建kmem_cache:
struct kmem_cache *kmem_cache_create(const char *name,
size_t size, size_t align,
unsigned long flags,
void (*ctor)(void *))
2、kmem_cache_destroy和kmem_cache_create相反,销毁创建的对应的slub的kmem_cache结构。
3、分配object的对象kmem_cache_alloc
void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
4、kmem_cache_free是kmem_cache_alloc的反操作。
5、例程:
void slab_test(void)
{
//create 16byte kmem_cache kmem_cache_16
struct kmem_cache *kmem_cache_16 = kmem_cache_create("kmem_cache_16", 16, 8, ARCH_KMALLOC_FLAGS, NULL);
//alloc buf points of 16 bytes of memory
char *buf = kmem_cache_alloc(kmem_cache_16, GFP_KERNEL);
//release the memory after use
kmem_cache_free(kmem_cache_16, buf);
//release kmem_cache
kmem_cache_destroy(kmem_cache_16);
}
四、SLUB分配原理
slub的分配原理可以从slub分配器的分配函数看起,kmem_cache_alloc -> slab_alloc -> slab_alloc_node ->
__slab_alloc -> ___slab_alloc ,其中整个分配的流程可以用如下图清晰的说明。首先从cpu 本地缓存池分配,如
果freelist不存在,就会转向cpu partial分配,如果cpu partial也没有可用对象,继续查看node partial,如果很不幸
也不没有可用对象的话,就只能从伙伴系统分配一个slab:
五、Kmalloc:
内核中使用的kmalloc函数也是基于slub分配器做的封装,按照内存块的2^order大小来创建slab描叙符。分配
内存的大小可以为16B、32B、64B、128B......32Mb,其对应的分配接口为:kmalloc-16、kmalloc-32、kmalloc-64。
在系统启动初期会调用create_kmalloc_caches ()创建多个管理不同大小对象的slab描叙符kmem_cache(包含16B、
32B、64B、128B......32Mb大小)。
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
if (!(flags & GFP_DMA)) {
int index = kmalloc_index(size);
if (!index)
return ZERO_SIZE_PTR;
return kmem_cache_alloc_trace(kmalloc_caches[index],
flags, size);
}
}
return __kmalloc(size, flags);
}
根据传入的对应的size选择对应的kmem_cahe,系统只能分配2^order大小的slab内存,如通过kmalloc(17,
GFP_KERNEL)申请内存,系统会从名称“kmalloc-32”管理的slab缓存池中分配一个对象。即使浪费了15Byte:
static __always_inline int kmalloc_index(size_t size)
{
if (!size)
return 0;
if (size <= KMALLOC_MIN_SIZE)
return KMALLOC_SHIFT_LOW;
if (KMALLOC_MIN_SIZE <= 32 && size > 64 && size <= 96)
return 1;
if (KMALLOC_MIN_SIZE <= 64 && size > 128 && size <= 192)
return 2;
if (size <= 8) return 3;
if (size <= 16) return 4;
if (size <= 32) return 5;
......
if (size <= 32 * 1024 * 1024) return 25;
if (size <= 64 * 1024 * 1024) return 26;
BUG();
/* Will never be reached. Needed because the compiler may complain */
return -1;
}
参考博文:
http://www.wowotech.net/memory_management/426.html
https://www.ibm.com/developerworks/cn/linux/l-cn-slub/
https://blog.csdn.net/lukuen/article/details/6935068
作者:frank_zyp
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文无所谓版权,欢迎转载。