内存池(memory pool)
是linux2.6的一个新的特性。基本上将,一个内存池允许一个内核成分,如块设备子系统,仅在内存不足的紧急情况下分配一些动态内存来使用。
内存池是动态内存的储备,只能被特定的内核成分(即池的“拥有者”)使用。拥有者通常不使用储备;但是,如果动态内存变得极其稀有以至于所有普通内存分配请求都将失败的话,那么作为最后的解决手段,内核成分就能调用特定的内存池函数提取储备得到的所需的额内存。因此,建设一个内存池就像手头放些灌装食物作为储备,当没有新鲜食物时就使用开罐器。
一个内存池常常叠加在slab分配器之上————也就是说,它被用来保留sla对象的储备。但是一般而言,内存池能被用来分配任何一种类型的动态内存,从整个页框到使用kmalloc()分配的小内存区。因此,我们将一般内存池处理的内存单元看着“内存元素”、
内存池由:mempool_t对象描述,它的字段如下表:
类型名称 说明
spinlock_t lock 用来保护对象字段的自旋锁
int min_nr 内存池中元素的最大个数
intcurr_nr当前内存池中元素的个数
void ** elements 指向一个数组的指针,该数组由指向保留元素的指针组成
void * pool_data 池的拥有者可得到的私有数据
mempool_alloc_t * alloc 分配一个元素的门路
mempool_free_t * free 释放一个元素的门路
wait_queue_head_t wait 当内存池为空时使用的等待队列
min_nr字段存放了内存池中元素的初始个数。换句话说,存放该字段中的值代表了内存元素的个数。内存池的拥有者确信能从内存分配器得到这个数目。curr_nr字段总是低于或者等于min_nr。它存放了内存池中当前包含的内存元素个数。内存元素自身被一个指针数组引用,指针数组的地址存放在elements字段中。
alloc和free门路与基本的内存分配器进行交互,分别勇于得到和释放一个内存元素,两个门路可以是拥有内存池的内核成分提供的定制函数。
当内存元素为slab对象时,alloc和free门路一般由mempool_alloc_slab()和mempool_free_slab()函数实现,他们只是分别kmem_cache_alloc()和kmem_cache_free()函数。在这种情况下,mempool_t对象的pool_data字段存放了slab告诉缓存描述符的地址。
mempool_create()函数建设一个新的内存池,它接管的参数为内存元素的个数min_nr、实现alloc和free方式的函数的地址和赋给pool_data字段的任意值。该函数得到min_nr个元素,相反地,mempool_destriy()函数释放池中所有内存元素,然后释放元素数组和mempool_t对象自己。
为了从内存池分配一个元素,内核调用mempool_alloc()函数,将mempool_t对象的地址和内存非配标志传递给它。函数本质上依据参数所指定的内存分配标志,试图通过调用alloc方法从基本内存分配器中分配一个内存元素。内存池得到内存元素,当然,在内存不足的情况下过多的分配会用尽内存池:在这种情况下,如果__GFP_WAIT标志没有置位,则mempool_alloc()阻塞当前进程直到有一个内存元素被释放到内存池中。
相反地,为了释放一个元素到内存池,内核调用mempool_free()函数。如果内存池未满(curr_min小于min_nr),则函数将元素加到内存池中,否则,mempool_free()调用free方法来释放元素到基本内存分配器。