内存资源池存储管理属于固定大小内存管理系统,内存池中内存块的分配和回收是基于第一级内存管理系统的,因为内存池中内存块是由第一级内存管理的算法所确定的。
内存池存储管理系统主要用于操作系统的一些常用结构的内存管理。例如线程控制块TCB、事件控制块ECB等,这些结构在系统运行过程中,必然会用到,而且会频繁地建立和释放。
使用第一级管理系统当然可以满足这些需求,为什么还要用内存资源池这种机制来进一步管理这些结构,对其进行内存分配和回收呢?
虽然第一级内存管理算法单次分配和回收内存的效率已经很高,但是频繁地回收和释放还是要消耗一定的时间。
如果可以事先分配一些常用结构大小的内存,并把它们组织起来形成内存资源池,那么当操作系统真正需要的时候只需要将这些指针返回就可以了。在操作系统使用完这些结构并且销毁时,就可以把这些结构所占用的内存还给内存资源池,而不用进行真正的内存回收,这样整体的效率就提高了。
每一类资源(如线程控制块TCB结构)可以拥有多个资源池,每个资源池只为一种类型的资源所使用(内存体现就是相同大小的内存块,由前面的伙伴算法确定)。
资源池控制块Pool_ctr负责一类资源的管理,一个资源池控制块会对应多个资源池。
如图所示,包含两个资源池Pool1、Pool2。
开始的时候,系统会根据需要为每一类资源控制块(如TCB)分配一些资源池,一旦资源池里的资源用完时,可以重新申请一个资源池,然后挂载到空闲资源池链表上。
每个资源池对应一个Pool结构,这个结构有两个重要的指针base_adr和res_free,分别用来指示资源对象数组的基址和空闲资源对象,每个资源对象对应一个资源控制块,如线程控制块TCB。
如果某资源池的资源对象都用完,res_free会指向NULL。
// 资源池控制块
typedef struct{
unsigned int type;//表示资源类型,如线程控制块资源、事件资源、时间数据块资源、驱动块资源
unsigned int size; //资源大小,一般就是结构体的大小,如线程控制块TCB的大小,用sizeof(acoral_thread_t)这种形式赋值
unsigned int num_per_pool;//每个资源池对象的个数,因为资源池管理的资源是由第一级内存系统(伙伴系统)分配而来的,为了最大限度地使用内存,减少内部碎片,资源对象的个数是用户指定的最大值和伙伴系统分配的内存所包含的对象个数共同决定的,例如,伙伴系统的基本内存块1KB,资源的大小1KB,用户一个资源池包含20个资源,这样算下来需要分配20KB,但伙伴系统中还能分配2^i^哥基本内存块的大小,所以会为之分配32KB,32KB包含32个资源对象。从这里可以看出,资源池真正分配的对象的个数往往大于等于用户指定的资源对象的个数
unsigned int num; //已分配的资源池的个数
unsigned int max_pools; //最多可以分配多少个资源池
acoral_list_t *free_pools; //空闲资源池链表
acoral_list_t *pools,list[2]; //资源池链表
unsigned char *name;
}acoral_pool_ctrl_t;
//资源池
typedef struct{
void *base_adr;//有两个作用,在资源池空闲时,指向下一个资源池,否则为它管理的资源的基地址
void *res_free;//表示此资源池管理的空闲资源对象链表头
int id; //此资源池的ID
unsigned int size; //表示资源的大小,等同于pool_ctrl的size
unsigned int num;//资源池管理的资源个数,等同于pool_ctrl的num_per_pool
unsigned int position;//暂时没用
unsigned int free_num;//剩余的资源对象个数
acoral_pool_ctrl_t *ctrl; //此资源池对应的资源控制块
acoral_list_t ctrl_list;//资源池链表结点
acoral_list_t free_list;//空闲资源池链表结点
}acoral_pool_t;
为了实现资源池的管理,aCoral定义了资源对象
typedef struct{
int id;
int next_id;
}acoral_res_t;
每个资源池有一个ID,当资源池空闲时,ID的高16位表示该资源对象在资源池的编号,分配后表示该资源的ID,next_id为空闲链表指针,空闲时该16位指向下一个空闲的资源对象编号,分配完后,就没有意义了,属于资源ID的一部分。
在能够使用资源内存池以前,首先要通过acoral_create_pool()创建资源内存池
unsigned int acoral_create_pool(acoral_pool_ctrl_t *pool_ctrl)
{
acoral_pool_t *pool;
if(pool_ctrl->num >= pool_ctrl->max_pools)
return ACORAL_RES_MAX_POOL;
pool = acoral_get_free_pool();//获取一个空闲资源池结构体acoral_pool_t,这个内存池结构体是静态分配的,是一个数组,个数可配置,但运行过程中不可增加
if(pool == NULL)
return ACORAL_RES_NO_POOL;
pool->id = pool_ctrl->type << ACORAL_RES_TYPE_BIT | pool->id;
pool->size = pool_ctrl->size;
pool->num = pool_ctrl->num_per_pool;
pool->base_adr = (void *)acoral_malloc(pool->size * pool->num);
if(pool->base_adr == NULL)
return ACORAL_RES_NO_MEM;
pool->res_free = pool->base_adr;
pool->free_num = pool->num;
pool->ctrl = pool_ctrl;
acoral_pool_res_init(pool); //初始化资源内存池管理的资源对象
acoral_list_add2_tail(&pool->ctrl->list, pool_ctrl->pools);//将此资源池插入资源池链表
acoral_list_add2_tail(&pool->free->list, pool_ctrl->free_pools);//将此资源池插入空闲资源池链表
pool_ctrl->num++;//增加资源池控制块的资源池个数
return 0;
}
内存池结构体,是一个数组,但为了分配和回收快速,将其组织成一个链表,需要通过acoral_pool_res_init()进行初始化。
void acoral_pool_res_init(acoral_pool_t *pool)
{
acoral_res_t *res;
unsigned int i;
unsigned char *pblk;
unsigned int blks;
blks = pool->num;
res = (acoral_res_t *)pool->base_adr;
pblk = (unsigned char *)pool->base_adr + pool->size;
for(i=0; i<(blks-1); i++)
{
res->id = i << ACORAL_REX_INDEX_INIT_BIT; //ID的高16位表示该资源在资源池的编号
res->next_id = i+1;
res = (acoral_res_t *)pblk;
pblk += pool->size;
}
res->id = blks-1 << ACORAL_RES_INDEX_INIT_BIT;
res->next_id = 0;
}
当资源池被创建并被初始化以后,便可为系统所使用。
分配线程空间时提到:线程分配空间函数acoral_alloc_thread()通过调用acoral_get_res()为线程的资源控制块分配空间“return (acoral_thread_t *)acoral_get_res(&acoral_thread_pool_ctrl);”传入的参数为线程的资源控制块acoral_pool_ctrl_t acoral_thread_pool_ctrl;
acoral_res_t *acoral_get_res(acoral_pool_ctrl_t *pool_ctrl)
{
acoral_list_t *first;
acoral_res_t *res;
acoral_pool_t *pool;
acoral_enter_critical();
first = pool_ctrl->free_pools->next; //从空闲资源池链表上取下一个pool
if(acoral_list_empty(first))//如果该结点等于链表头,则意味着无空闲资源池,需要通过前面的acoral_create_pool获取一个资源池并挂载到空闲链表上
{
if(acoral_create_pool(pool_ctrl))
{
acoral_exit_critical();
return NULL;
}
else
{
first = pool_ctrl->free_pools->next;
}
}
pool = list_entry(first, acoral_pool_t, free_list);
res = (acoral_res_t *)pool->res_free;
pool->res_free = (void *)((unsigned char *)pool->base_adr + res->next_id * pool_size);
res->id = (res->id >> (ACORAL_RES_INDEX_INIT_BIT - ACORAL_RES_INDEX_BIT)) & ACORAL_RES_INDEX_MASK | pool->id; //修改资源id
pool->free_num--;
if (!pool->free_num)
{
acoral_list_del(&pool->free_list);
}
acoral_exit_critical();
return res;
}
以上是资源池的分配,如果系统运行过程中,某个资源不再使用(如线程控制块),则通过acoral_release_res()释放
void acoral_release_res(acoral_res_t *res)
{
acoral_pool_t *pool
unsigned int index;
void *tmp;
acoral_pool_ctrl_t *pool_ctrl;
if(res == NULL || acoral_get_res_by_id(res->id) != res)
return;
pool = acoral_get_pool_by_id(res->id);
if(pool == NULL)
{
acoral_print("res release err\n");
return;
}
pool_ctrl = pool->ctrl;
if((void *)res < pool->base_adr)
{
acoral_print("Err Res\n");
return;
}
index = (((unsigned int)res - (unsigned int)pool->base_adr) / pool->size);
if(index >= pool->num)
{
acoral_print("Err Res\n");
return;
}
tmp = pool->res_free;
pool->res_free = (void *)res;
res->id = index << ACORAL_RES_INDEX_INIT_BIT;
res->next_id = ((acoral_res_t *)tmp)->id >> ACORAL_RES_INDEX_INIT_BIT;
pool->free_num++;
if (acoral_list_empty(&pool->free_list))
acoral_list_add(&pool->free_list, pool_ctrl->free_pools);
return;
}