Linux内核内存池管理技术实现分析
来源:互联网 发布:php多文件上传代码 编辑:程序博客网 时间:2024/06/06 17:54
一.Linux系统内核内存管理简介
Linux采用“按需调页”算法,支持三层页式存储管理策略。将每个用户进程4GB长度的虚拟内存划分成固定大小的页面。其中0至3GB是用户态空间,由各进程独占;3GB到4GB是内核态空间,由所有进程共享,但只有内核态进程才能访问。
Linux将物理内存也划分成固定大小的页面,由数据结构page管理,有多少页面就有多少page结构,它们又作为元素组成一个数组mem_map[]。
slab:在操作系统的运作过程中,经常会涉及到大量对象的重复生成、使用和释放问题。对象生成算法的改进,可以在很大程度上提高整个系统的性能。在Linux系统中所用到的对象,比较典型的例子是inode、task_struct等,都又这些特点。一般说来,这类对象的种类相对稳定,每种对象的数量却是巨大的,并且在初始化与析构时要做大量的工作,所占用的时间远远超过内存分配的时间。但是这些对象往往具有这样一个性质,即他们在生成时,所包括的成员属性值一般都赋成确定的数值,并且在使用完毕,释放结构前,这些属性又恢复为未使用前的状态。因此,如果我们能够用合适的方法使得在对象前后两次背使用时,在同一块内存,或同一类内存空间,且保留了基本的数据结构,就可以大大提高效率。slab算法就是针对上述特点设计的。
slab算法思路中最基本的一点被称为object-caching,即对象缓存。其核心做法就是保留对象初始化状态的不变部分,这样对象就用不着在每次使用时重新初始化(构造)及破坏(析构)。
面向对象的slab分配中有如下几个术语:
l
l
完全块:没有空闲对象。
部分块:只分配了部分对象空间,仍有空闲对象。
空闲块:没有分配对象,即整个块内对象空间均可分配。
在申请新的对象空间时,如果缓冲区中存在部分块,那么首先查看部分块寻找空闲对象空间,若未成功再查看空闲块,如果还未成功则为这个对象分配一块新的slab块。
l
二.内存池的数据结构
Linux内存池是在2.6版内核中加入的,主要的数据结构定义在mm/mempool.c中。
typedef struct mempool_s {
} mempool_t;
三.内核缓存区和内存池的初始化
上面提到,内存池的使用是与特定类型的内存对象缓存区相关联的。例如,在系统rpc服务中,系统初始化时,会为rpc_buffers预先分配缓存区,调用如下语句:
rpc_buffer_slabp = kmem_cache_create("rpc_buffers",
调用kmem_cache_create函数从系统缓存区cache_cache中获取长度为RPC_BUFFER_MAXSIZE的缓存区大小的内存,作为rpc_buffer使用的缓存区。而以后对rpc操作的所有数据结构内存都是从这块缓存区申请,这是linux的slab技术的要点,而内存池也是基于这段缓存区进行的操作。
一旦rpc服务申请到了一个缓存区rpc_buffer_slabp以后,就可以创建一个内存池来管理这个缓存区了:
rpc_buffer_mempool = mempool_create(RPC_BUFFER_POOLSIZE,
mempool_create函数就是内存池创建函数,负责为一类内存对象构造一个内存池,传递的参数包括,内存池大小,定制的内存分配函数,定制的内存析构函数,这个对象的缓存区指针。下面是mempool_create函数的具体实现:
mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
{