嵌入式实时操作系统的设计与开发(内存资源池存储管理)

news2024/11/20 12:43:15

内存资源池存储管理

内存资源池存储管理属于固定大小内存管理系统,内存池中内存块的分配和回收是基于第一级内存管理系统的,因为内存池中内存块是由第一级内存管理的算法所确定的。

内存池存储管理系统主要用于操作系统的一些常用结构的内存管理。例如线程控制块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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1120166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

位操作符^以及正负数在计算机中的存储

(数据是怎么在计算机中存储的)​ 正数和负数在内存中都是以补码的形式存储的&#xff0c;但不同的是正数的原码&#xff0c;补码&#xff0c;反码都是相同的&#xff0c;而负数的原码&#xff0c;补码和反码是不同的。 负数的原码&#xff0c;补码&#xff0c;反码之间存在什么…

神仙级价格:腾讯云双十一服务器优惠价格表来了

2023腾讯云双十一服务器优惠价格表多少钱一年&#xff1f;轻量服务器2核2G3M、2核2G4M、2核4G5M、4核8G12M、8核16G18M、16核32G28M和云服务器CVM标准型S5实例优惠价格&#xff0c;腾讯云百科今年双11服务器价格会在当前的价格基础上享受个9折优惠&#xff0c;可领券 https://c…

【Java】一只小菜坤的编程题之旅【4】

文章目录 1丶合并两个有序链表2丶栈的压入、弹出序列3丶设计循环队列4丶最小栈 1丶合并两个有序链表 小菜坤的答案&#xff1a; class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode newHeadnew ListNode(0);ListNode tmpnewHead;while…

Git的介绍和命令汇总

目录 一、git介绍 1、git的工作区域 2、git中文件的四种状态 二、常用命令 1、基础命令 2、提交类命令 3、删除类命令 4、分支类相关命令 5、 查看类相关命令 6、撤销类命令 一、git介绍 1、git的工作区域 在Git中&#xff0c;有四个工作区域&#xff1a;工作区域&am…

k8s认证

1. 证书介绍 服务端保留公钥和私钥&#xff0c;客户端使用root CA认证服务端的公钥 一共有多少证书&#xff1a; *Etcd&#xff1a; Etcd对外提供服务&#xff0c;要有一套etcd server证书Etcd各节点之间进行通信&#xff0c;要有一套etcd peer证书Kube-APIserver访问Etcd&a…

算法学习之 背包01问题 , 备战leecode

来看题目 我们分析一下题目&#xff0c;首先我们要排序&#xff0c;这有助于我们得到最大的值&#xff0c;我们要得到一个递推公式 代码如下: class Solution { public:int maxSatisfaction(vector<int>& satisfaction) {int n satisfaction.size();vector<v…

【数据结构复习之路】串 (超详细讲解) 严蔚敏版

专栏&#xff1a;数据结构复习之路 复习完上面一章【线性表】【栈和队列】&#xff0c;我们接着复习串&#xff0c;这篇文章我写的非常详细且通俗易懂&#xff0c;看完保证会带给你不一样的收获。如果对你有帮助&#xff0c;看在我这么辛苦整理的份上&#xff0c;三连一下啦 目…

42917-2023 消光制品用聚氯乙烯树脂

1 范围 本文件规定了消光制品用聚氯乙烯树脂的分类、技术要求、取样、试验方法、检验规则及标志、随行 文件、包装、运输和贮存。 本文件适用于氯乙烯与交联剂悬浮共聚所制得的用于生产消光制品的聚氯乙烯树脂。 2 规范性引用文件 下列文件中的内容通过文中的规范性引用而…

通过高通量测序评估金针菇(双孢蘑菇)生产过程中的微生物演替

1.1 Title:Microbial succession during button mushroom (Agaricus bisporus) production evaluated via high-throughput sequencing 1.2 作者&#xff1a;Ban Ga-Hee 1.3 机构&#xff1a;Ewha Womans University 1.4 期刊&#xff1a;Food Microbiology 1.5 分区/影响因…

连接器信号完整性仿真教程 八

连接器信号完整性仿真主要是解算S参数及与之相关的参数&#xff0c;查看仿真结果相对于HFSS&#xff0c;其操作要简单得多。不需要复杂的操作&#xff0c;基本上左边导航树中&#xff0c;就可直接打开需要查看的仿真结果。下面以B to B Connector仿真结果实例演示&#xff0c;详…

何为心理承受能力?如何提高心理承受能力?

心理承受能力&#xff0c;也可以理解为人的抗压能力&#xff0c;指的是承受压力&#xff0c;承受逆境的能力。人的一生其实就是在不断的解决问题&#xff0c;见招拆招&#xff0c;遇到问题解决问题&#xff0c;在我们不断学习和锻炼的过程中&#xff0c;提高了我们解决问题的效…

Python之解析式和生成器表达式

Python之解析式和生成器表达式 列表解析式 列表解析式List Comprehension&#xff0c;也叫列表推导式。 语法 [返回值 for 元素 in 可迭代对象 if 条件]使用中括号[]&#xff0c;内部是for循环&#xff0c;if条件语句可选返回一个新的列表 列表解析式是一种语法糖 编译器…

Vue中如何处理表单输入验证?

在Vue中,能使用多种方式处理表单输入验证。以下是几种常见的方法: 1:使用Vue的指令和表达式: Vue提供了一些内置的指令和表达式,可以直接在模板中进行表单验证。例如,你可以使用v-model指令结合条件表达式来验证输入内容。 <template><div><input v-mod…

微软官方推出的四款工具,太实用了,值得收藏

目录 一、Officeplus——丰富的办公资源库 二、微软数学求解器 三、微软内置edge浏览器 四、Microsoft To-Do 办公待办神器 所以今天小编给大家分享4个微软官方推出的实用工具&#xff0c;每一个都非常好用&#xff0c;对于大家日常办公&#xff0c;非常有必要&#xff0c;感兴…

【C++深入浅出】C/C++内存管理(教你如何new到对象)

一. 前言 前面我们学习了有关C类和对象的知识&#xff0c;学会了如何构建一个完整的类&#xff0c;这些类都是存储在栈空间上的。在C语言中&#xff0c;我们不仅可以在栈上定义变量&#xff0c;也可以对堆上的空间进行管理&#xff0c;在接下来的几期中&#xff0c;我们的目标就…

idea + Docker-Compose 实现自动化打包部署(仅限测试环境)

一、修改docker.service文件&#xff0c;添加监听端口 vi /usr/lib/systemd/system/docker.service ExecStart/usr/bin/dockerd -H fd:// --containerd/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock重启docker服务 systemctl daemo…

一个进程最多可以创建多少个线程基本分析

前言 ​话不多说&#xff0c;先来张脑图~ linux 虚拟内存知识回顾 虚拟内存空间长啥样 在 Linux 操作系统中&#xff0c;虚拟地址空间的内部又被分为内核空间和用户空间两部分&#xff0c;不同位数的系统&#xff0c;地址空间的范围也不同。比如最常见的 32 位和 64 位系统&…

四大特性模块(module)

module的动机 C20中新增了四大特性之一的模块(module)&#xff0c;用以解决传统的头文件在编译时间及程序组织上的问题。 modules 试图解决的痛点 能最大的痛点就是编译慢, 头文件的重复替换, 比如你有多个翻译单元, 每一个都调用了 iostream, 就得都处理一遍. 预处理完的源…

muduo异步日志库

文章目录 一、日志库模型参考 一、日志库模型 muduo日志库是异步高性能日志库&#xff0c;其性能开销大约是前端每写一条日志消息耗时1.0us~1.6us。 采用双缓冲区&#xff08;double buffering&#xff09;交互技术。基本思想是准备2部分buffer&#xff1a;A和B&#xff0c;前…

英语——分享篇——每日200词——2601-2800

2601——resistant——[rɪzɪstənt]——adj.抵抗的——resistant——resi热死(拼音)st石头(拼音)ant蚂蚁(熟词)——热死了石头上的蚂蚁还在抵抗——The body may be less resistant if it is cold. ——天冷时&#xff0c;身体的抵抗力会下降。 2602——prospect——[prɒspe…