持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情
伙伴系统在分配内存时是以物理页面为单位的,在实际中有很多内存需求是以字节为单位的,那么如果我们需要分配以字节为单位的小内存块,该如何分配呢?slab分配器就是用来解决小内存块分配问题的,也是内存分配中非常重要的角色之一。 slab分配器最终还使用伙伴系统来分配实际的物理页面,只不过slab分配器在这些连续的物理页面上实现了自己的机制,以此来对小内存块进行管理。
slab分配器产生的背景
内核常常需要分配几十字节的小内存块,若为其分配一个物理页面,则非常浪费内存。早期Linux内核实现了以2n字节为大小的内存块分配机制,这个机制非常类似于伙伴系统。这个简单的机制虽然减少了内存浪费,但是并不高效。 一个更好的机制是Sun公司发明的slab机制,最早实现在Solaris 2.4操作系统中。slab机制有如下新特性。
把分配的内存块当作对象(object)来看待。对象可以自定义构造函数(constructor)和析构函数(destructor)来初始化对象的内容并释放对象的内容。 slab对象被释放之后不会马上丢弃而是继续保留在内存中,可能稍后会被用到,这样不需要重新向伙伴系统申请内存。 slab机制可以根据特定大小的内存块来创建slab描述符,如内存中常见的数据结构、打开文件对象等,这样可以有效地避免内存碎片的产生,也可以快速获得频繁访问的数据结构。另外,slab机制也支持按2n字节大小分配内存块。 slab机制创建了多层的缓冲池,充分利用了空间换时间的思想,未雨绸缪,有效地解决了效率问题。
slab分配器提供如下接口函数来创建、释放slab描述符和分配缓存对象。
#创建slab描述符
struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,
unsigned long flags, void (*ctor)(void *))
#释放slab描述符
void kmem_cache_destroy(struct kmem_cache *s)
#分配缓存对象
void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags);
#释放缓存对象
void kmem_cache_free(struct kmem_cache *, void *);
- kmem_cache_create()函数中有如下参数。
- name:slab描述符的名称。
- size:缓存对象的大小。
- align:缓存对象需要对齐的字节数。
- flags:分配掩码。
- ctor:对象的构造函数。