在嵌入式操作系统中,多次使用malloc()和free()会将原来很大的一块连续存储区域,逐渐地分成许多非常小且彼此不相邻的存储区域,这就是存储碎片。由于存储碎片数量的不断增加,程序到后来可能无法分得一块连续的存储区域。另外,由于存储空间管理算法的原因,要得到一块连续的存储块,且大小足以满足malloc()函数的要求,malloc()和free()函数要执行的时间也是不确定的。
μC/OS-III提供了一种替代malloc()和free()函数的方法,将连续的大块存储空间进行分区管理,每个分区中包含整数个大小相同的存储块,由μC/OS-III管理。通过该种机制,使应用程序可以获得固定大小的存储块。由此,分配和释放存储块花费的时间是常数,是固定可知的。
函数 | 含义 |
---|---|
OSMemCreate() | 创建一个存储分区 |
OSMemGet() | 从存储分区中获得一个存储块 |
OSMemPut() | 将一个存储块归还到存储分区中 |
1 创建存储分区
在使用存储分区之前,必须首先创建存储分区,并告知μC/OS-III一些存储分区的基本信息以便其管理存储空间。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200710091739170.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0dST1dfMTc=,size_16,color_FFFFFF,t_70#pic_center) (1)当创建存储分区时,应用代码提供存储分区控制块OS_MEM的地址,一般情况下,**存储分区控制块从静态存储空间中分配**,但也可以通过malloc()动态分配。 (2)OSMemCreate()函数将需要管理的连续存储空间整理成单向链表,并将指针保存到OS_MEM结构体的开头。 (3)每个存储块的容量不得小于保存一个指针变量所需的空间,根据链表的要求,每个块中需要有指向下一块的指针。/*静态分配存储控制空间*/
OS_MEM MyPartition; /*应用程序为存储分区控制块分配空间*/
/*应用程序需要为被分成存储空间块的存储分区分配空间
可以通过静态分配也可以通过动态malloc()函数分配
但是该存储空间只能分配不能释放,其他任务的生存可能依赖该存储空间*/
CPU_INT08U MyPartitionStorage[12][100];
void main(void) /*创建存储分区的最佳时机之一是在main函数中,开始多任务之前*/
{
OS_ERR err;
...
OSInit(&err);
/*Check error*/
OSMemCreate((OS_MEM*) &MyPatition, /*将存储分区控制块的地址传入,用户不能引用OS_MEM数据结构的内部成员*/
(CPU_CHAR*) "My Partition", /*为存储分区控制块指定一个ASCII字符串别名*/
(void*) &MyPartitionStorage[0][0], /*要分配的存储空间的基地址*/
(OS_MEM_QTY) 12, /*设定存储空间有多少个存储块可用*/
(OS_MEM_SIZE) 100, /*设定存储空间中每个存储块的大小*/
(OS_ERR*) &err); /*错误返回码*/
/*Check error*/
...
OSStart(&err);
/*Check error*/
}
/*动态分配存储控制空间*/
OS_MEM* MyPartitionPtr; /*动态分配存储控制块基地址*/
...
void main(void)
{
OS_ERR err;
void* P_Stroage; /*动态分配的存储空间基地址*/
...
OSInit(&err);
/*Check error*/
MyPartitionPtr = (OS_MEM*)malloc(sizeof(OS_MEM));
if(MyPartitionPtr != (OS_MEM*)0)
{
P_Stroage = malloc(sizeof(CPU_INT08U)*12*100); /*动态分配12*100个CPU_INT08U个存储空间*/
if(P_Stroage != (void*)0)
{
OSMemCreate((OS_MEM*) MyPartitionPtr, /*将存储分区控制块的地址传入,用户不能引用OS_MEM数据结构的内部成员*/
(CPU_CHAR*) "My Partition", /*为存储分区控制块指定一个ASCII字符串别名*/
(void*) P_Stroage, /*要分配的存储空间的基地址*/
(OS_MEM_QTY) 12, /*设定存储空间有多少个存储块可用*/
(OS_MEM_SIZE) 100, /*设定存储空间中每个存储块的大小*/
(OS_ERR*) &err); /*错误返回码*/
/*Check error*/
}
}
}
2 从分区中获取存储块
OS_MEM MyPartition; /*存储分区控制块应该能被使用该分区的任务和ISR读/写*/
CPU_INT08U* MyDataBlkPtr; /*获得分区块的前提是,用户应该知道分区块的大小,以防止数据溢出*/
void MyTask(void* p_arg)
{
OS_ERR err;
...
while(DEF_ON)
{
...
MyDataBlkPtr = (CPU_INT08U*)OSMemGet(OS_MEM*)&MyPartition, (OS_ERR*)&err);
if(err == OS_ERR_NONE) /*通过检查错误码 判断是否有空闲块分为当前任务*/
/*存储分区分出一个块,并将这个块的基地址赋给了MyDataBlkPtr*/
...
}
}
3 将存储块归还到分区中
OS_MEM MyPartiton;
CPU_INT08U* MyDataBlkPtr;
void MyTask(void* p_arg)
{
OS_ERR err;
...
while(DEF_ON)
{
...
/*当有多个存储分区时,要对存储块属于哪个存储分区进行检查*/
OSSemPut((OS_MEM*)MyPartiton, (void*)MyDataBlkPtr, (OS_ERR*)&err);
if(err == OS_ERR_NONE)
/*存储块归还成功*/
}
}