内存管理之slab分配器
基本思想
与传统的内存管理模式相比, slab 缓存分配器提供了很多优点。首先,内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配。slab 缓存分配器通过对类似大小的对象进行缓存而提供这种功能,从而避免了常见的碎片问题。slab 分配器还支持通用对象的初始化,从而避免了为同一目而对一个对象重复进行初始化。最后,slab 分配器还可以支持硬件缓存对齐和着色,这允许不同缓存中的对象占用相同的缓存行,从而提高缓存的利用率并获得更好的性能。
说明:
每个缓存都包含了一个 slabs 列表,这是一段连续的内存块(通常都是页面)。存在 3 种 slab:
slabs_full - 完全分配的 slab
slabs_partial - 部分分配的 slab
slabs_empty - 空 slab,或者没有对象被分配
slabs_empty 列表中的 slab 是进行回收(reaping)的主要备选对象。正是通过此过程,slab 所使用的内存被返回给操作系统供其他用户使用。
slab 列表中的每个 slab 都是一个连续的内存块(一个或多个连续页),它们被划分成一个个对象。这些对象是从特定缓存中进行分配和释放的基本元素。注意 slab 是 slab 分配器进行操作的最小分配单位,因此如果需要对 slab 进行扩展,这也就是所扩展的最小值。通常来说,每个 slab 被分配为多个对象。
由于对象是从 slab 中进行分配和释放的,因此单个 slab 可以在 slab 列表之间进行移动。例如,当一个 slab 中的所有对象都被使用完时,就从 slabs_partial 列表中移动到 slabs_full 列表中。当一个 slab 完全被分配并且有对象被释放后,就从 slabs_full 列表中移动到 slabs_partial 列表中。当所有对象都被释放之后,就从 slabs_partial 列表移动到 slabs_empty 列表中。
API 函数
http://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/index.html
现在来看一下能够创建新 slab 缓存、向缓存中增加内存、销毁缓存的应用程序接口(API)以及 slab 中对对象进行分配和释放操作的函数。
第一个步骤是创建 slab 缓存结构,您可以将其静态创建为:
struct struct kmem_cache *my_cachep;
然后其他 slab 缓存函数将使用该引用进行创建、删除、分配等操作。kmem_cache 结构包含了每个中央处理器单元(CPU)的数据、一组可调整的(可以通过 proc 文件系统访问)参数、统计信息和管理 slab 缓存所必须的元素。
kmem_cache_create
内核函数 kmem_cache_create 用来创建一个新缓存。这通常是在内核初始化时执行的,或者在首次加载内核模块时执行。其原型定义如下:
struct kmem_cache *
kmem_cache_create( const char *name, size_t size, size_t align,
unsigned long flags;
void (*ctor)(void*, struct kmem_cache *, unsigned long),
void (*dtor)(void*, struct kmem_cache *, unsigned long));
name 参数定义了缓存名称,proc 文件系统(在 /proc/slabinfo 中)使用它标识这个缓存。
size 参数指定了为这个缓存创建的对象的大小, align 参数定义了每个对象必需的对齐。 flags 参数指定了为缓存启用的选项。这些标志如表 1 所示。
ctor 和 dtor 参数定义了一个可选的对象构造器和析构器。构造器和析构器是用户提供的回调函数。当从缓存中分配新对象时,可以通过构造器进行初始化。
在创建缓存之后, kmem_cache_create 函数会返回对它的引用。注意这个函数并没有向缓存分配任何内存。相反,在试图从缓存(最初为空)分配对象时,refill 操作将内存分配给它。当所有对象都被使用掉时,也可以通过相同的操作向缓存添加内存。
kmem_cache_destroy
内核函数 kmem_cache_destroy 用来销毁缓存。这个调用是由内核模块在被卸载时执行的。在调用这个函数时,缓存必须为空。
void kmem_cache_destroy( struct kmem_cache *cachep );
kmem_cache_alloc
要从一个命名的缓存中分配一个对象,可以使用 kmem_cache_alloc 函数。调用者提供了从中分配对象的缓存以及一组标志:
void kmem_cache_alloc( struct kmem_cache *cachep, gfp_t flags );
这个函数从缓存中返回一个对象。注意如果缓存目前为空,那么这个函数就会调用 cache_alloc_refill 向缓存中增加内存。 kmem_cache_alloc 的 flags 选项与 kmalloc 的 flags 选项相同。 给出了标志选项的部分列表。
kmem_cache_zalloc
内核函数 kmem_cache_zalloc 与 kmem_cache_alloc 类似,只不过它对对象执行 memset 操作,用来在将对象返回调用者之前对其进行清除操作。
kmem_cache_free
要将一个对象释放回 slab,可以使用 kmem_cache_free。调用者提供了缓存引用和要释放的对象。
void kmem_cache_free( struct kmem_cache *cachep, void *objp );
kmalloc 和 kfree
内核中最常用的内存管理函数是 kmalloc 和 kfree 函数。这两个函数的原型如下:
void *kmalloc( size_t size, int flags );
void kfree( const void *objp );
注意在 kmalloc 中,惟一两个参数是要分配的对象的大小和一组标志(请参看 表 2 中的部分列表)。但是 kmalloc 和 kfree 使用了类似于前面定义的函数的 slab 缓存。kmalloc 没有为要从中分配对象的某个 slab 缓存命名,而是循环遍历可用缓存来查找可以满足大小限制的缓存。找到之后,就(使用 __kmem_cache_alloc)分配一个对象。要使用 kfree 释放对象,从中分配对象的缓存可以通过调用 virt_to_cache 确定。这个函数会返回一个缓存引用,然后在
__cache_free 调用中使用该引用释放对象。
其他函数
slab 缓存 API 还提供了其他一些非常有用的函数。 kmem_cache_size 函数会返回这个缓存所管理的对象的大小。您也可以通过调用 kmem_cache_name 来检索给定缓存的名称(在创建缓存时定义)。缓存可以通过释放其中的空闲 slab 进行收缩。这可以通过调用 kmem_cache_shrink 实现。注意这个操作(称为回收)是由内核定期自动执行的(通过 kswapd)。
unsigned int kmem_cache_size( struct kmem_cache *cachep );
const char *kmem_cache_name( struct kmem_cache *cachep );
int kmem_cache_shrink( struct kmem_cache *cachep );
内存管理之slab分配器的更多相关文章
- Linux内存管理 (5)slab分配器
专题:Linux内存管理专题 关键词:slab/slub/slob.slab描述符.kmalloc.本地/共享对象缓冲池.slabs_partial/slabs_full/slabs_free.ava ...
- Linux内核笔记——内存管理之slab分配器
内核版本:linux-2.6.11 内存区和内存对象 伙伴系统是linux用于满足对不同大小块内存分配和释放请求的解决方案,它为slab分配器提供页框分配请求的实现. 如果我们需要请求具有连续物理地址 ...
- Linux内存管理之slab分配器
slab分配器是什么? 参考:http://blog.csdn.net/vanbreaker/article/details/7664296 slab分配器是Linux内存管理中非常重要和复杂的一部分 ...
- 把握linux内核设计思想(十二):内存管理之slab分配器
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流.请勿用于商业用途] 上一节最后说到对于小内存区的请求,假设採用伙伴系统来进行分配,则会在页内产生非 ...
- Linux内存管理之bootmem分配器
为什么要使用bootmem分配器,内存管理不是有buddy系统和slab分配器吗?由于在系统初始化的时候需要执行一些内存管理,内存分配的任务,这个时候buddy系统,slab分配器等并没有被初始化好, ...
- 启动期间的内存管理之引导分配器bootmem--Linux内存管理(十)
在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检 ...
- Linux内核笔记--内存管理之用户态进程内存分配
内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...
- Linux内存管理 - slab分配器和kmalloc
本文目的在于分析Linux内存管理机制的slab分配器.内核版本为2.6.31.1. SLAB分配器 内核需要经常分配内存,我们在内核中最常用的分配内存的方式就是kmalloc了.前面讲过的伙伴系统只 ...
- linux内核分析之内存管理
1.struct page /* Each physical page in the system has a struct page associated with * it to keep tra ...
随机推荐
- [OpenGL] mac上运行NateRobin的OpenGL教程找不到 data file 解决方案
之前买的OpenGL编程指南第七版一直没看,最近开始看了,然后按照教程推荐的去指定网址下载NateRobin的OpenGL教程,但发现网址已经提示Error:404了, 然后谷歌搜索到可用的下载网址为 ...
- PHP测试题讲解(20161027)
注: 关联数组 关联数组,它的每个 ID 键都关联一个值.在存储有关具体命名的值的数据时,使用数值数组不是最好的做法.通过关联数组,我们可以把值作为键,并向它们赋值. 例子 1 在本例中,我们使用一个 ...
- jsonpath读取json数据格式公用方法!!!
import java.util.LinkedHashMap; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Pred ...
- Python中参数是传值,还是传引用?
在 C/C++ 中,传值和传引用是函数参数传递的两种方式,在Python中参数是如何传递的?回答这个问题前,不如先来看两段代码. 代码段1: def foo(arg): arg = 2 print(a ...
- CAS进行https到http的改造方案,结合cookie源码分析
先说具体的改造方案: 服务端: 一.CAS Server端的修改 1.找到cas\WEB-INF\deployerConfigContext.xml 对以下Bean增加参数p:requireSecur ...
- Apache保持连接
HTTP协议是基于TCP协议之上的,在进行HTTP连接之前,要先进行TCP连接(TCP三次握手),在连接结束后要对TCP连接进行终止(TCP四次断开).建立与关闭连接对于HTTP协议而言会消耗很多的内 ...
- 百度推出 MIP Shell 链接
在站长将站点 MIP 化时,需要关注 URL 的一共有三个:MIP URL, MIP-Cache URL 以及 MIP-Shell URL. 从 URL 说起 在互联网中,URL 定义页面的地址,每个 ...
- 通过composer管理工具安装laravel
当安装好composer管理工具后,将composer的bin目录添加至环境变量中(PATH),方便在任意目录下执行composer命令. 方法1:我们通过laravel工具安装laravel 首先, ...
- CSS.01 -- 选择器及相关的属性文本、文字、字体、颜色、
与html相比,Css支持更丰富的文档外观,Css可以为任何元素的文本和背景设置颜色:允许在任何元素外围设置边框:允许改变文本的大小,装饰(如下划线),间隔,甚至可以确定是否显示文本. 什么是CSS? ...
- Unity3D对弈游戏:狼吃羊游戏
简介 中文名:狼与羊 英文名称:Wolves&Sheep 游戏类型:休闲/棋类 玩家人数:单人或双人 游戏下载:Windows.Android 游戏描述:童年时与小伙伴常玩的一种游戏,游戏简单 ...