- 简述
- 在嵌入式系统中,内存分配应根据系统特点选择使用
- 动态内存分配算法:普通业务系统,动态内存上限取决于硬件,使用效率高
- 静态内存分配算法:可靠性非常高的系统,需要考虑内存上限,使用效率低
- uC/OS内存管理是采用内存池的方式进行管理
- 静态划分一大块连续空间做为内存管理的空间,内部划分若干块
- 使用的时候就从内存池中获取内存块,使用完将其放回
- 核心机制:
- 内存池的创建
- 分配
- 释放
- 在嵌入式系统中,内存分配应根据系统特点选择使用
- 存储空间分类:
- 内部存储空间:RAM(本节所讲)
- 外部存储空间:ROM
- 运行机制
- 内存池(Memory Pool)是一种用于分配大量大小相同的内存对象的技术,可以加快内存分配/释放的速度
- 系统编译时,编译器静态划分一个数组做为系统的内存池,将其分成大小相等的内存块,通过链表链接起来
- 先创建内存池才能使用内存块,
- 内存控制块
- 内存池名称
- 起始地址
- 空闲内存块列表
- 大小
- 内存块数量
- 空闲内存块数量
- 应用场景
- 在不确定数组应该有多大的时候,静态方法,会浪费大量的内存空间,有可能会引起下标越界
- uC/OS将系统静态分配的大数组做为内存池,然后分配固定大小的内存块
- 如果某个任务内存需求很大,只能按照最大的内存块分配
- 常用函数
- OSMemCreate(); 内存创建函数
- OSMemGet(); 内存申请函数
- OSMemPut(); 内存释放函数
- 例程
- 创建
//创建内存管理对象 mem OSMemCreate( (OS_MEM *)&mem, //指向内存管理对象 (CPU_CHAR *)"mem for test",//命名内存管理对象 (void *)ucArray, //内存分区的首地址 (OS_MEM_QTY )3, //内存分区中内存块数目 (OS_MEM_SIZE )20, //内存块的字节数目 (OS_ERR *)&err); //返回错误类型
- 申请
/************************************************** * 函数名:static void AppTaskKey(void *p_arg) * 描述 :按键检测 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :内部调用 **************************************************/ static void AppTaskKey(void *p_arg) { OS_ERR err; char * p_mem_blk; uint32_t ulcount = 0; (void)p_arg; for(;;) { //向mem获取内存块 p_mem_blk = OSMemGet( (OS_MEM *)&mem, //指向内存管理对象 (OS_ERR *)&err); //返回错误类型 sprintf(p_mem_blk, "%d", ulcount ++); //向内存块存取计数值 OSTaskQPost( (OS_TCB *)&AppTaskLedTCB, //目标任务控制块 (void *)p_mem_blk, //消息内容的首地址 (OS_MSG_SIZE )strlen(p_mem_blk), // 消息长度 (OS_OPT )OS_OPT_POST_FIFO, //发送到任务消息队列的入口 (OS_ERR *)&err); //返回错误类型 OSTimeDlyHMSM ( 0, 0, 1, 0, OS_OPT_TIME_DLY, & err ); //每1s发送一次 } }
- 释放
/************************************************** * 函数名:static void AppTaskLed(void *p_arg) * 描述 :led应用 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :内部调用 **************************************************/ static void AppTaskLed(void *p_arg) { OS_ERR err; CPU_INT32U cpu_clk_freq; CPU_TS ts; OS_MSG_SIZE msg_size; char * pMsg; (void)p_arg; cpu_clk_freq = BSP_CPU_ClkFreq(); //获取系统时钟 for(;;) { pMsg = OSTaskQPend( (OS_TICK )0, //无期限等待 (OS_OPT )OS_OPT_PEND_BLOCKING, //没有消息任务就阻塞 (OS_MSG_SIZE *)&msg_size, //返回消息长度 (CPU_TS *)&ts, //返回消息被发送的时间戳 (OS_ERR *)&err); //返回错误类型 ts = OS_TS_GET() - ts; //计算时间差 LED1_TOGGLE; printf("\r\n 接收到的消息内容为: %s,长度是: %d 字节 \r\n", pMsg,msg_size); printf("\r\n 任务消息从被发送到被接收的时间差是: %d us \r\n", ts / (cpu_clk_freq / 1000000)); //退还内存块 OSMemPut( (OS_MEM *)&mem, //指向内存管理对象 (void *)pMsg, //内存块的首地址 (OS_ERR *)&err); //返回错误类型 } }
- 创建
- 下载验证
- 总结
- uC/OS的内存分配算法是只允许用户分配固定大小的内存块,使用完将其放回内存池中;
- 内存池中的内存块是通过单链表连接起来的,创建的内存块地址是连续的,空闲的内存块地址上不一定连续
- uC/OS将系统静态分配的大数组做为内存池,然后分配固定大小的内存块
- uC/OS的内存分配只能解决内存利用率的问题
- 参考资料:
- 正点原子《STM32F767 UCOS开发手册》
- 野火《uC/OS-III内核应用与开发》
- 《嵌入式实时操作系统 uC/OS-II原理及应用(第二版)》
- 官方源码
- 硬件平台:
- 正点原子阿波罗F767
- 软件平台:
- MDK5.2.5
- 库版本:
- TM32Cube_FW_F7_V1.4.0
- uC/OS-III版本
- UCOSIII 3.04