UCOSII-内存管理

UCOSII-内存管理UCOSII 内存管理对于程序运行资源分配很有帮助 在需要使用大量内存空间时需要用到内存管理 需要时申请 用完释放 UCOSII 系统提供内存管理函数 供用户使用 本文详细介绍了内存管理的相关函数及配置 供大家参考 谢谢

一.前言

二.内存控制块

操作系统以分区为单位来管理动态内存,而任务以内存块为单位来获得和释放动态内存。内存分区及内存块的使用情况则由内存控制块来记录。

1.内存分区及内存控制块的定义

在内存中定义一个内存分区及其内存块的方法非常简单,只需定义一个二维数组即可。例如:

INT8U IntMemBuf[10][10]; //定义一个内存区,包含10个内存块,每个内存块由10个u8数据构成 

2.内存控制块OS_MEM的结构

#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u) typedef struct os_mem { 
    /* MEMORY CONTROL BLOCK */ void *OSMemAddr; /* 内存分区的指针 */ void *OSMemFreeList; /* 内存控制块链表指针 */ INT32U OSMemBlkSize; /* 内存块的长度 */ INT32U OSMemNBlks; /* 分区内内存块的数目 */ INT32U OSMemNFree; /* 分区内当前可分配的内存块的数目 */ #if OS_MEM_NAME_EN > 0u INT8U *OSMemName; /* Memory partition name */ #endif } OS_MEM; 

3.空内存控制块链表

在UCOSII初始化时,会调用内存控制块的初始化函数OS_MemInit()定义并初始化一个空内存控制块链表
在这个空内存控制块链表中,一个有OS_MAX_MEM_PART(在文件OS_CFG.H中定义的常数)个空内存控制块。这些空内存控制块的指针成员OSMemFreeList暂时作为指向下一个空内存控制块指针。
空内存控制块链表的结构如下图所示:
在这里插入图片描述
每当应用程序需要创建一个内存分区时,系统就会从空内存控制块链表中摘取一个控制块,而把链表的头指针OSMemFreeList指向下一个空内存控制块;而每当应用程序释放一个内存分区时,则会把该分区对应的内存控制块归还给空内存控制块链表。








三.动态内存的管理

OS_MEM *OSMemCreate (void *addr, //内存分区的起始地址 INT32U nblks, //分区中内存块的数目 INT32U blksize, //每个内存块的字节数 INT8U *perr) //错误信息 

请求获得内存块函数OSMemGet();

void *OSMemGet (OS_MEM *pmem, //内存分区的指针 INT8U *perr) //错误信息 

释放内存块函数OSMemPut();

INT8U OSMemPut (OS_MEM *pmem, //内存分区的指针 void *pblk) //待释放内存块的指针 

查询动态内存分区状态函数OSMemQuery();

#if OS_MEM_QUERY_EN > 0u INT8U OSMemQuery (OS_MEM *pmem, //待查询的内存控制块的指针 OS_MEM_DATA *p_mem_data); //存放分区状态信息的结构的指针 

其中p_mem_data是一个OS_MEM_DATA 类型的结构。定义如下:

typedef struct os_mem_data { 
    void *OSAddr; /* 内存分区的指针 */ void *OSFreeList; /* 分区内内存块链表的头指针 */ INT32U OSBlkSize; /* 内存块的长度 */ INT32U OSNBlks; /* 分区内内存块的数目 */ INT32U OSNFree; /* 分区内空闲内存块的数目 */ INT32U OSNUsed; /* 已被分配的内存块数目 */ } OS_MEM_DATA; 

四.内存管理应用代码(基于stm32f4)

/UCOSII任务堆栈设置*/ //1.START 任务 //设置任务优先级 #define START_TASK_PRIO 10 //开始任务的优先级设置为最低 //设置任务堆栈大小 #define START_STK_SIZE 128 //创建任务堆栈空间  OS_STK START_TASK_STK[START_STK_SIZE]; //任务函数接口 void start_task(void *pdata); //2.main_task主任务 //任务优先级 #define MAIN_TASK_PRIO 4 //任务堆栈大小  #define MAIN_STK_SIZE 128 //任务堆栈  OS_STK MAIN_TASK_STK[MAIN_STK_SIZE]; //任务函数 void main_task(void *pdata); //3.memmanage_task内存管理任务 //任务优先级 #define MEMMANAGE_TASK_PRIO 5 //任务堆栈大小 #define MEMMANAGE_STK_SIZE 128 //任务堆栈 OS_STK MEMMANAGE_TASK_STK[MEMMANAGE_STK_SIZE]; //任务函数 void memmanage_task(void *pdata); /定义存储区/ //定义一个存储区(内部) OS_MEM *INTERNAL_MEM; //定义内存控制块指针 //存储区中存储块数量 #define INTERNAL_MEM_NUM 5 //每个存储块大小 //由于一个指针变量占用4字节所以块的大小一定要为4的倍数 //而且必须大于一个指针变量(4字节)占用的空间,否则的话存储块创建不成功 #define INTERNAL_MEMBLOCK_SIZE 100  //存储区的内存池,使用内部RAM u8 Internal_RamMemp[INTERNAL_MEM_NUM][INTERNAL_MEMBLOCK_SIZE]; //划分分区及内存块 //定义一个存储区(外部) OS_MEM *EXTERNAL_MEM; //定义内存控制块指针 //存储区中存储块数量 #define EXTRENNAL_MEM_NUM 5 //每个存储块大小 //由于一个指针变量占用4字节所以块的大小一定要为4的倍数 //而且必须大于一个指针变量(4字节)占用的空间,否则的话存储块创建不成功 #define EXTERNAL_MEMBLOCK_SIZE 100 //存储区的内存池,使用外部SRAM(位置:0X) u8 External_RamMemp[EXTRENNAL_MEM_NUM][EXTERNAL_MEMBLOCK_SIZE] __attribute__((at(0X)));//划分分区及内存块 /main主函数/ int main(void) { 
    delay_init(168); //延时初始化  uart_init(); //串口初始化波特率为 LED_Init(); //初始化与LED连接的硬件接口  KEY_Init(); //key初始化 LCD_Init(); //LCD初始化  FSMC_SRAM_Init(); //初始化SRAM ucos_load_main_ui(); //加载主UI1 OSInit(); //初始化UCOSII  OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务 OSStart(); //开始执行UCOS程序 } //开始任务 void start_task(void *pdata) { 
    u8 err; OS_CPU_SR cpu_sr=0; pdata = pdata; OSStatInit(); //初始化统计任务.这里会延时1秒钟左右  OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断)  //创建一个内部存储分区 INTERNAL_MEM=OSMemCreate(Internal_RamMemp,INTERNAL_MEM_NUM,INTERNAL_MEMBLOCK_SIZE,&err); //创建一个外部存储分区,使用外部SRAM(位置:0X) EXTERNAL_MEM=OSMemCreate(External_RamMemp,EXTRENNAL_MEM_NUM,EXTERNAL_MEMBLOCK_SIZE,&err); OSTaskCreate(main_task,(void *)0,(OS_STK*)&MAIN_TASK_STK[MAIN_STK_SIZE-1],MAIN_TASK_PRIO); //在开始任务中创建main任务  OSTaskCreate(memmanage_task,(void *)0,(OS_STK*)&MEMMANAGE_TASK_STK[MEMMANAGE_STK_SIZE-1],MEMMANAGE_TASK_PRIO); //在开始任务中创建memmanage_task任务  OSTaskSuspend(START_TASK_PRIO); //挂起起始任务. OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断) } //主任务的任务函数(完成内存的申请及释放) void main_task(void *p_arg) { 
    u8 key,num,i=0; static u8 external_memget_num; u8 *internal_buf[5]; u8 *external_buf; u8 err; while(1) { 
    key = KEY_Scan(0); //扫描按键 switch(key) { 
    case WKUP_PRES: //按下KEY_UP键:申请内部内存 for(i=0;i<5;i++) { 
    internal_buf[i]=OSMemGet(INTERNAL_MEM,&err); //循环申请五次内存并放在internal_buf[i]缓存区内 if(err == OS_ERR_NONE) //内存申请成功 { 
    sprintf((char*)internal_buf[i],"internal_buf[%d]=%d\r\n",i,i);//在申请到的内存区域内放置数据 printf("%s",internal_buf[i]); //显示出来 printf("internal_buf[%d]内存申请之后的地址为:%#x\r\n",i,(u32)(internal_buf[i])); printf("internal_buf[%d]内存申请成功!\r\n",i); } else if(err == OS_ERR_MEM_NO_FREE_BLKS) //内存块不足 { 
    LCD_ShowString(30,180,200,16,16,"INTERNAL_MEM Empty! "); } delay_ms(500); //延时500ms,也就是每500ms申请一次内存,共五次 } break; case KEY1_PRES: for(i=5;i>0;i--) { 
    if(internal_buf[i-1] != NULL) //internal_buf不为空就释放内存 { 
    OSMemPut(INTERNAL_MEM,internal_buf[i-1]);//循环5次释放内部内存 printf("internal_buf[%d]内存释放之后的地址为:%#x\r\n",i-1,(u32)(internal_buf[i-1])); printf("internal_buf[%d]内存释放成功!\r\n",i-1); internal_buf[i-1]=NULL; //释放后的缓存区指向NULL! } else if(internal_buf[i-1] == NULL) //内存已释放 { 
    LCD_ShowString(30,180,200,16,16,"INTERNAL_MEM released! "); } delay_ms(500); //延时500ms,也就是每500ms申请一次内存,共五次 } break; case KEY2_PRES: //按下KEY2键:申请外部内存 external_buf=OSMemGet(EXTERNAL_MEM,&err); if(err == OS_ERR_NONE) //内存申请成功 { 
    printf("external_buf内存申请之后的地址为:%#x\r\n",(u32)(external_buf)); LCD_ShowString(30,260,200,16,16,"Memory Get success! "); external_memget_num++; POINT_COLOR = BLUE; sprintf((char*)external_buf,"EXTERNAL_MEM Use %d times",external_memget_num); LCD_ShowString(30,276,200,16,16,external_buf); POINT_COLOR = RED; } if(err == OS_ERR_MEM_NO_FREE_BLKS) //内存块不足 { 
    LCD_ShowString(30,260,200,16,16,"EXTERNAL_MEM Empty! "); } break; case KEY0_PRES: if(external_buf != NULL) //external_buf不为空就释放内存 { 
    OSMemPut(EXTERNAL_MEM,external_buf);//释放外部内存 printf("external_buf内存释放之后的地址为:%#x\r\n",(u32)(external_buf)); LCD_ShowString(30,260,200,16,16,"Memory Put success! "); } break; } num++; if(num==50) { 
    num=0; LED0 = ~LED0; } delay_ms(10); //延时10ms } } //内存管理任务(显示总的内存缓存块数以及剩余缓存块的数) void memmanage_task(void *p_arg) { 
    LCD_ShowString(5,164,200,16,16,"Total: Remain:"); LCD_ShowString(5,244,200,16,16,"Total: Remain:"); while(1) { 
    POINT_COLOR = BLUE; LCD_ShowxNum(53,164,INTERNAL_MEM->OSMemNBlks,1,16,0); LCD_ShowxNum(125,164,INTERNAL_MEM->OSMemNFree,1,16,0); LCD_ShowxNum(53,244,EXTERNAL_MEM->OSMemNBlks,1,16,0); LCD_ShowxNum(125,244,EXTERNAL_MEM->OSMemNFree,1,16,0); POINT_COLOR = RED; delay_ms(100); //延时100ms } } 

五.总结

1.通过定义一个二维数组在内存中划分一个内存分区,其中的所有内存块应大小相等。
2.系统通过与内存分区相关联的内存控制块来对内存分区进行管理。
3.划分及创建内存分区根据需要由应用程序负责,而系统只提供了可供任务调用的相关函数。
4.在UCOSII中,在使用和释放动态内存的安全性方便,要由应用程序全权负责。






版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220843.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午7:31
下一篇 2026年3月17日 下午7:31


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号