把握linux内核设计思想(十二):内存管理之slab分配器
【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流。请勿用于商业用途】
上一节最后说到对于小内存区的请求,假设採用伙伴系统来进行分配,则会在页内产生非常多空暇空间无法使用。因此产生slab分配器来处理对小内存区(几十或几百字节)的请求。Linux中引入Slab的主要目的是为了降低对伙伴算法的调用次数。
内核常常重复使用某一内存区。比如。仅仅要内核创建一个新的进程,就要为该进程相关的数据结构(task_struct、打开文件对象等)分配内存区。当进程结束时。收回这些内存区。由于进程的创建和撤销很频繁。linux把那些频繁使用的页面保存在快速缓存中并又一次使用。
slab分配器基于对象进行管理,同样类型的对象归为一类(如进程描写叙述符就是一类),每当要申请这样一个对象。slab分配器就分配一个空暇对象出去,而当要释放时,将其又一次保存在slab分配器中,而不是直接返回给伙伴系统。
对于频繁请求的对象。创建适当大小的专用对象来处理。对于不频繁的对象。用一系列几何分布大小的对象来处理(详见通用对象)。
Slab分配模式把对象分组放进缓冲区,为缓冲区的组织和管理与硬件快速缓存的命中率密切相关,因此。Slab缓冲区并不是由各个对象直接构成。而是由一连串的“大块(Slab)”构成,而每一个大块中则包括了若干个同种类型的对象。这些对象或已被分配。或空暇。实际上。缓冲区就是主存中的一片区域,把这片区域划分为多个块。每块就是一个Slab,每一个Slab由一个或多个页面组成,每一个Slab中存放的就是对象。
slab相关数据结构:
缓冲区数据结构使用kmem_cache结构来表示。
struct kmem_cache {
/* 1) per-cpu data, touched during every alloc/free */struct array_cache *array[NR_CPUS];
/* 2) Cache tunables. Protected by cache_chain_mutex */unsigned int batchcount;unsigned int limit;unsigned int shared;unsigned int buffer_size;u32 reciprocal_buffer_size;
/* 3) touched by every alloc & free from the backend */unsigned int flags; /* constant flags */unsigned int num; /* # of objs per slab *//* 4) cache_grow/shrink *//* order of pgs per slab (2^n) */unsigned int gfporder;/* force GFP flags, e.g. GFP_DMA */gfp_t gfpflags;size_t colour; /* cache colouring range */unsigned int colour_off; /* colour offset */struct kmem_cache *slabp_cache;unsigned int slab_size;unsigned int dflags; /* dynamic flags *//* constructor func */void (*ctor)(void *obj);/* 5) cache creation/removal */const char *name;struct list_head next;/* 6) statistics */
#ifdef CONFIG_DEBUG_SLABunsigned long num_active;unsigned long num_allocations;unsigned long high_mark;unsigned long grown;unsigned long reaped;unsigned long errors;unsigned long max_freeable;unsigned long node_allocs;unsigned long node_frees;unsigned long node_overflow;atomic_t allochit;atomic_t allocmiss;atomic_t freehit;atomic_t freemiss;/** If debugging is enabled, then the allocator can add additional* fields and/or padding to every object. buffer_size contains the total* object size including these internal fields, the following two* variables contain the offset to the user object and its size.*/int obj_offset;int obj_size;
#endif /* CONFIG_DEBUG_SLAB *//** We put nodelists[] at the end of kmem_cache, because we want to size* this array to nr_node_ids slots instead of MAX_NUMNODES* (see kmem_cache_init())* We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache* is statically defined, so we reserve the max number of nodes.*/struct kmem_list3 *nodelists[MAX_NUMNODES];/** Do not add fields after nodelists[]*/
};
当中struct kmem_list3结构体链接slab,共享快速缓存。其定义例如以下:
/** The slab lists for all objects.*/
struct kmem_list3 {struct list_head slabs_partial; /* partial list first, better asm code */struct list_head slabs_full;struct list_head slabs_free;unsigned long free_objects;unsigned int free_limit;unsigned int colour_next; /* Per-node cache coloring */spinlock_t list_lock;struct array_cache *shared; /* shared per node */struct array_cache **alien; /* on other nodes */unsigned long next_reap; /* updated without locking */int free_touched; /* updated without locking */
};
该结构包括三个链表:slabs_partial、slabs_full、slabs_free,这些链表包括缓冲区全部slab。slab描写叙述符struct slab用于描写叙述每一个slab:
/** struct slab** Manages the objs in a slab. Placed either at the beginning of mem allocated* for a slab, or allocated from an general cache.* Slabs are chained into three list: fully used, partial, fully free slabs.*/
struct slab {struct list_head list;unsigned long colouroff;void *s_mem; /* including colour offset */unsigned int inuse; /* num of objs active in slab */kmem_bufctl_t free;unsigned short nodeid;
};
一个新的缓冲区使用例如以下函数创建:
struct kmem_cache *kmem_cache_create (const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *));
函数创建成功会返回一个指向所创建缓冲区的指针;撤销一个缓冲区调用例如以下函数:
<span style="font-family:Microsoft YaHei;">void kmem_cache_destroy(struct kmem_cache *cachep);</span>
上面两个函数都不能在中断上下文中使用。由于它可能睡眠。
在创建来缓冲区之后,能够通过下列函数获取对象:
/*** kmem_cache_alloc - Allocate an object* @cachep: The cache to allocate from.* @flags: See kmalloc().** Allocate an object from this cache. The flags are only relevant* if the cache has no available objects.*/
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{void *ret = __cache_alloc(cachep, flags, __builtin_return_address(0));trace_kmem_cache_alloc(_RET_IP_, ret,obj_size(cachep), cachep->buffer_size, flags);return ret;
}
该函数从给点缓冲区cachep中返回一个指向对象的指针。
假设缓冲区的全部slab中都没有空暇对象,那么slab层必须通过kmem_getpages()获取新的页。參数flags传递给_get_free_pages()。
<span style="font-family:Microsoft YaHei;">static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid);</span>
释放对象使用例如以下函数:
/*** kmem_cache_free - Deallocate an object* @cachep: The cache the allocation was from.* @objp: The previously allocated object.** Free an object which was previously allocated from this* cache.*/
void kmem_cache_free(struct kmem_cache *cachep, void *objp)
{unsigned long flags;local_irq_save(flags);debug_check_no_locks_freed(objp, obj_size(cachep));if (!(cachep->flags & SLAB_DEBUG_OBJECTS))debug_check_no_obj_freed(objp, obj_size(cachep));__cache_free(cachep, objp);local_irq_restore(flags);trace_kmem_cache_free(_RET_IP_, objp);
}
假设你要频繁的创建非常多同样类型的对象,就要当考虑使用slab快速缓存区。
实际上上一节所讲kmalloc()函数也是使用slab分配器分配的。
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{struct kmem_cache *cachep;void *ret;if (__builtin_constant_p(size)) {int i = 0;if (!size)return ZERO_SIZE_PTR;#define CACHE(x) \if (size <= x) \goto found; \else \i++;
#include <linux/kmalloc_sizes.h>
#undef CACHEreturn NULL;
found:
#ifdef CONFIG_ZONE_DMAif (flags & GFP_DMA)cachep = malloc_sizes[i].cs_dmacachep;else
#endifcachep = malloc_sizes[i].cs_cachep;ret = kmem_cache_alloc_notrace(cachep, flags);trace_kmalloc(_THIS_IP_, ret,size, slab_buffer_size(cachep), flags);return ret;}return __kmalloc(size, flags);
}
kfree函数实现例如以下:
/*** kfree - free previously allocated memory* @objp: pointer returned by kmalloc.** If @objp is NULL, no operation is performed.** Don't free memory not originally allocated by kmalloc()* or you will run into trouble.*/
void kfree(const void *objp)
{struct kmem_cache *c;unsigned long flags;trace_kfree(_RET_IP_, objp);if (unlikely(ZERO_OR_NULL_PTR(objp)))return;local_irq_save(flags);kfree_debugcheck(objp);c = virt_to_cache(objp);debug_check_no_locks_freed(objp, obj_size(c));debug_check_no_obj_freed(objp, obj_size(c));__cache_free(c, (void *)objp);local_irq_restore(flags);
}
最后。结合上一节。看看分配函数的选择:
假设须要连续的物理页,就能够使用某个低级页分配器或kmalloc()。
假设想从高端内存进行分配,使用alloc_pages()。
假设不须要物理上连续的页,而不过虚拟地址上连续的页,那么就是用vmalloc。
假设要创建和销毁非常多大的数据结构,那么考虑建立slab快速缓存。
把握linux内核设计思想(十二):内存管理之slab分配器相关推荐
- 《Linux内核设计与实现》内存管理札记
1.页 芯作为物理页存储器管理的基本单元,MMU(内存管理单元)中的页表,从虚拟内存的角度来看,页就是最小单位. 内核用struct page结构来标识系统中的每个物理页.它的定义例如以下: flag ...
- Linux内存管理之SLAB分配器
注:本文讲述的SLAB相关代码是基于Linux内核v4.7,代码网址. 1.SLAB分配器的由来 在讲SLAB分配器之前先说两个概念: 内部碎片和外部碎片. 外部碎片指的是还没有被分配出去(不属于任何 ...
- Linux内核源码分析之内存管理
本文站的角度更底层,基本都是从Linux内核出发,会更深入.所以当你都读完,然后再次审视这些功能的实现和设计时,我相信你会有种豁然开朗的感觉. 1.页 内核把物理页作为内存管理的基本单元. 尽管处理器 ...
- 内存管理之slab分配器
基本思想 与传统的内存管理模式相比, slab 缓存分配器提供了很多优点.首先,内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配.slab 缓存分配器通过对类似大小的对象进行缓存而提 ...
- 《深入理解Linux内核》笔记5:内存管理
本文介绍内核如何给自己分配物理内存并管理.对应<深入>第8章. 在<深入>第2章"内存寻址"(或者是我博客中的这篇文章,点这里)中,已经介绍了内核如何给自己 ...
- 【Linux 内核】Linux 操作系统结构 ( Linux 内核在操作系统中的层级 | Linux 内核子系统及关系 | 进程调度 | 内存管理 | 虚拟文件系统 | 网络管理 | 进程间通信 )
文章目录 一.Linux 内核在操作系统中的层级 二.Linux 内核子系统 三.Linux 内核子系统之间的关系 一.Linux 内核在操作系统中的层级 Linux 内核 所在层级 : 整个计算机系 ...
- linux内核编程13期:内存管理
内管管理子系统是Linux内核中比较复杂的一个模块,也是很多Linux开发者的"梦魇",无论是Linux新手.运维.应用开发者,还是有多年经验的驱动工程师,在学习内存管理时,面对错 ...
- Linux内核分析 - 网络[十二]:UDP模块 - socket
内核版本:2.6.34 这部分内容在于说明socket创建后如何被内核协议栈访问到,只关注两个问题:sock何时插入内核表的,sock如何被内核访问的.对于核心的sock的插入.查找函数都给出了流程图 ...
- Linux内核分析 - 网络[十二]:UDP模块 - 收发
内核版本:2.6.34 UDP报文接收 UDP报文的接收可以分为两个部分:协议栈收到udp报文,插入相应队列中:用户调用recvfrom()或recv()系统调用从队列中取出报文,这里的 ...
最新文章
- 可视化应用实战案例:metacoder-相关进化树图的绘制
- python opencv 批量将视频转化为图片
- 页面缓存导致数据错误
- 《好未来编程题》 输入n个整数,输出出现次数大于等于数组长度一半的数
- sql中数据类型的转换(自己写比较累哈,偷偷懒,转下别人的)
- ScreenFlow for mac(屏幕录像软件)
- 2022年武汉CMMI3-CMMI5认证企业名录
- 怎么在Windows系统中制作Mac系统U盘启动盘?
- 考研作息时间安排表(19通信考研党)
- 苹果个人开发者账号出售_国内苹果企业级开发者账号申请需要多久
- 解决数据库数据粘贴到excel中换行、换列问题
- ERROR in ./node_modules/element-plus/es/components/menu-item-group/style/css2.mjs 2:0-54
- 滚动抽奖html怎么做的,抽奖.html
- com lofter android,LOFTER
- flutter packages get 慢 解决方案
- python图片批量处理(水印、重命名)
- python日记_递归
- 仿微信、微博发朋友圈,文字+图片+视频
- 大时代势不可挡,隔行扫描已经消失。BT.709色彩空间也开始离我们远去
- 妈妈再也不用担心我的面试,满满干货指导