精华内容
下载资源
问答
  • 【UCOSIII】UCOSIII的存储管理

    千次阅读 2018-07-05 20:40:02
    通常应用程序可以调用ANSI C编译器malloc()和free()函数来动态分配和释放内存,但是在嵌入式事实操作系统中最好不要这么做,多次这样操作会把原来很大一块连续存储区域逐渐地分割成许多非常小并且彼此不相邻...

    UCOSIII内存管理简介

    作为一个RTOS操作系统,内存管理是必备的功能,因此UCOSIII也就内存管理能力。通常应用程序可以调用ANSI C编译器的malloc()和free()函数来动态的分配和释放内存,但是在嵌入式事实操作系统中最好不要这么做,多次这样的操作会把原来很大的一块连续存储区域逐渐地分割成许多非常小并且彼此不相邻的存储区域,这就是存储碎片。存储碎片最终导致的结果就是,应用不能申请到大小合适的连续内存。

    UCOSIII中提供了一种替代malloc()和free()函数的方法,它提供了自己的动态内存方案。UCOIII将存储空间分成区和块,一个存储区有数个固定大小的块组成,如下图所示:

    一般存储区是固定的,在程序中可以用数组来表示一个存储区,比如u8 buffer[20][10]就表示一个有20个存储块,每个存储块10字节的存储区。如果我们定义的存储区在程序运行期间都不会被删除掉,一直有效,那么存储区内存也可以使用malloc()来分配。在创建存储区以后应用程序就可以获得固定大小的存储块。

    实际使用中我们可以根据应用程序对内存需求的不同建立多个存储区,每个存储区中有不同大小、不同数量的存储块,应用程序可以根据所需内存不同从不同的存储区中申请内存使用,使用完以后在释放到相应的存储区中。

     

    UCOSIII存储控制块

    UCOSIII中用存储控制块来表示存储区,存储控制块为OS_MEM。具体的定义为:

    struct os_mem {                                             /* MEMORY CONTROL BLOCK                                   */
        OS_OBJ_TYPE          Type;                              /* 类型   */
        void                *AddrPtr;                           /* 指向存储区起始地址   */
        CPU_CHAR            *NamePtr;
        void                *FreeListPtr;                       /* 指向空闲存储块   */
        OS_MEM_SIZE          BlkSize;                           /* 存储区中存储块大小,单位:字节  */
        OS_MEM_QTY           NbrMax;                            /* 存储区中总的存储块数   */
        OS_MEM_QTY           NbrFree;                           /* 存储区中空闲存储块数   */
    #if OS_CFG_DBG_EN > 0u
        OS_MEM              *DbgPrevPtr;
        OS_MEM              *DbgNextPtr;
    #endif
    };

    创建好的存储区如下图:

     

    UCOSIII存储管理相关API函数

    UCOSIII存储管理相关API函数
    函数 说明
    OSMemCreate() 创建一个存储分区
    OSMemGet() 从存储分区中获得一个存储块
    OSMemPut() 将一个存储块归还到存储分区中

    存储区创建

    创建存储区使用函数OSMemCreate(),函数原型如下:

    void  OSMemCreate (OS_MEM       *p_mem,                        //指向存储区控制块地址
                       CPU_CHAR     *p_name,                        //指向存储区的名字
                       void         *p_addr,                    //存储区所有存储空间基地址
                       OS_MEM_QTY    n_blks,                    //存储区中存储块个数
                       OS_MEM_SIZE   blk_size,                    //存储块大小
                       OS_ERR       *p_err)
    {
        OS_MEM_QTY     i;
        OS_MEM_QTY     loops;
        CPU_INT08U    *p_blk;
        void         **p_link;
        CPU_SR_ALLOC();
    
    #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
        if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* 中断中是不能调用函数OSMemCreate()来创建存储区的    */
           *p_err = OS_ERR_MEM_CREATE_ISR;
            return;
        }
    #endif
    
    #if OS_CFG_ARG_CHK_EN > 0u
        if (p_addr == (void *)0) {                              /* 存储区空间基地址不能为0   */
           *p_err   = OS_ERR_MEM_INVALID_P_ADDR;
            return;
        }
        if (n_blks < (OS_MEM_QTY)2) {                           /* 存储区中存储块数量n_blks最少为2  */
           *p_err = OS_ERR_MEM_INVALID_BLKS;
            return;
        }
        if (blk_size < sizeof(void *)) {                        /* 每个存储块大小不小于一个指针大小,一个指针大小为4字节,因此每个存储块大小要大于4字节  */
           *p_err = OS_ERR_MEM_INVALID_SIZE;
            return;
        }
        align_msk = sizeof(void *) - 1u;
        if (align_msk > 0) {
            if (((CPU_ADDR)p_addr & align_msk) != 0u){          /* 判断存储区空间基地址是否4字节对齐,存储区的存储空间基地址必须4字节对齐  */
               *p_err = OS_ERR_MEM_INVALID_P_ADDR;
                return;
            }
            if ((blk_size & align_msk) != 0u) {                 /* 存储区中每个存储块的大小要是4的倍数  */
               *p_err = OS_ERR_MEM_INVALID_SIZE;
                return;
            }
        }
    #endif
    
        p_link = (void **)p_addr;                               /* Create linked list of free memory blocks               */
        p_blk  = (CPU_INT08U *)p_addr;
        loops  = n_blks - 1u;
        for (i = 0u; i < loops; i++) {
            p_blk +=  blk_size;
           *p_link = (void  *)p_blk;                            /* Save pointer to NEXT block in CURRENT block            */
            p_link = (void **)(void *)p_blk;                    /* Position     to NEXT block                             */
        }
       *p_link             = (void *)0;                         /* Last memory block points to NULL                       */
    
        OS_CRITICAL_ENTER();
        p_mem->Type        = OS_OBJ_TYPE_MEM;                   /* Set the type of object                                 */
        p_mem->NamePtr     = p_name;                            /* Save name of memory partition                          */
        p_mem->AddrPtr     = p_addr;                            /* Store start address of memory partition                */
        p_mem->FreeListPtr = p_addr;                            /* Initialize pointer to pool of free blocks              */
        p_mem->NbrFree     = n_blks;                            /* Store number of free blocks in MCB                     */
        p_mem->NbrMax      = n_blks;
        p_mem->BlkSize     = blk_size;                          /* Store block size of each memory blocks                 */
    
    #if OS_CFG_DBG_EN > 0u
        OS_MemDbgListAdd(p_mem);
    #endif
    
        OSMemQty++;
    
        OS_CRITICAL_EXIT_NO_SCHED();
       *p_err = OS_ERR_NONE;
    }

    内存申请

    使用函数OSMemGet()来获取存储块,函数原型如下:

    void  *OSMemGet (OS_MEM  *p_mem,                        //要使用的存储区
                     OS_ERR  *p_err)
    {
        void    *p_blk;
        CPU_SR_ALLOC();
    
    #ifdef OS_SAFETY_CRITICAL
        if (p_err == (OS_ERR *)0) {
            OS_SAFETY_CRITICAL_EXCEPTION();
            return ((void *)0);
        }
    #endif
    
    #if OS_CFG_ARG_CHK_EN > 0u
        if (p_mem == (OS_MEM *)0) {                             /* 判断存储区p_mem是否存在     */
           *p_err  = OS_ERR_MEM_INVALID_P_MEM;
            return ((void *)0);
        }
    #endif
    
        CPU_CRITICAL_ENTER();
        if (p_mem->NbrFree == (OS_MEM_QTY)0) {                  /* 判断存储区中是否还有空闲的存储块     */
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_MEM_NO_FREE_BLKS;                    /* No,  Notify caller of empty memory partition           */
            return ((void *)0);                                 /*      Return NULL pointer to caller                     */
        }
        p_blk              = p_mem->FreeListPtr;                /*  取出空闲存储块链表中第一个存储块   */
        p_mem->FreeListPtr = *(void **)p_blk;                   /*  空闲存储块链表头FreeListPtr就需要更新    */
        p_mem->NbrFree--;                                       /*      One less memory block in this partition           */
        CPU_CRITICAL_EXIT();
       *p_err = OS_ERR_NONE;                                    /*      No error                                          */
        return (p_blk);                                         /*      Return memory block to caller                     */
    }

    返回值:获取到的存储块地址。

    从上面的程序中我们可以看出UCOSIII自带的内存管理函数的局限性,每次申请内存的时候用户要先估计所申请的内存是否会超过存储区中存储块的大小。比如我们创建了一个有10个存储块,每个存储块大小为100字节的存储区buffer。这时我们应用程序需要申请一个10字节的内存,那么就可以使用函数OSMemGet()从存储区buffer中申请一个存储块。但是每个存储块有100个字节,但是应用程序只使用其中的10个字节,剩余的90个字节就浪费掉了,为了减少浪费我们可以创建一个每个存储块为10字节的存储区,这样就不会有内费了。

    但是,问题又来了,假设我们在程序的其他地方需要申请一个150字节的内存,但是存储区buffer的每个存储块只有100字节,显然存储区buffer不能满足程序的需求。有读者就会问可不可以在存储区中连续申请两个100字节的存储块,这样就有200字节的内存供应用程序使用了?想法是好想法,但是通过阅读函数OSMemGet()发现并没有提供这样的功能,OSMemGet()函数在申请内存的时候每次只取指定存储区的一个存储块!如果想申请150字节的内存就必须再新建一个每个存储块至少有150字节的存储区。

    通过上面的分析可以看出UCOSIII的内存管理很粗糙,不灵活,并不能申请指定大小的内存块。

    内存释放

    在UCOSIII中内存的释放可以使用函数OSMemPut()来完成,函数原型如下:

    void  OSMemPut (OS_MEM  *p_mem,                        //指向存储区控制块
                    void    *p_blk,                        //指向存储块
                    OS_ERR  *p_err)
    {
        CPU_SR_ALLOC();
    
    #ifdef OS_SAFETY_CRITICAL
        if (p_err == (OS_ERR *)0) {
            OS_SAFETY_CRITICAL_EXCEPTION();
            return;
        }
    #endif
    
    #if OS_CFG_ARG_CHK_EN > 0u
        if (p_mem == (OS_MEM *)0) {                             /* 检查存储区是否存在    */
           *p_err  = OS_ERR_MEM_INVALID_P_MEM;
            return;
        }
        if (p_blk == (void *)0) {                               /* 检查存储块是否存在     */
           *p_err  = OS_ERR_MEM_INVALID_P_BLK;
            return;
        }
    #endif
    
        CPU_CRITICAL_ENTER();
        if (p_mem->NbrFree >= p_mem->NbrMax) {                  /* 检查存储区空闲存储块数量是否大于存储区总存储块数量    */
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_MEM_FULL;
            return;
        }
        *(void **)p_blk    = p_mem->FreeListPtr;                /* 将要归还的存储块添加到空闲存储块链表中,这里是添加到表头的位置   */
        p_mem->FreeListPtr = p_blk;
        p_mem->NbrFree++;                                       /* One more memory block in this partition                */
        CPU_CRITICAL_EXIT();
       *p_err              = OS_ERR_NONE;                       /* Notify caller that memory block was released           */
    }

     

    UCOSIII实际例程

    存储管理实验

    例程要求:设计一个程序,创建两个存储区,这两个存储区分别创建STM32的内部RAM和外部SRAM中,通过开发板上的按键来申请和释放内存。

    例子:

    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "lcd.h"
    #include "key.h"
    #include "sram.h"
    #include "beep.h"
    #include "includes.h"
    
    //UCOSIII中以下优先级用户程序不能使用,ALIENTEK
    //将这些优先级分配给了UCOSIII的5个系统内部任务
    //优先级0:中断服务服务管理任务 OS_IntQTask()
    //优先级1:时钟节拍任务 OS_TickTask()
    //优先级2:定时任务 OS_TmrTask()
    //优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
    //优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
    
    //任务优先级
    #define START_TASK_PRIO		3
    //任务堆栈大小	
    #define START_STK_SIZE 		128
    //任务控制块
    OS_TCB StartTaskTCB;
    //任务堆栈	
    CPU_STK START_TASK_STK[START_STK_SIZE];
    //任务函数
    void start_task(void *p_arg);
    
    //任务优先级
    #define MAIN_TASK_PRIO		4
    //任务堆栈大小	
    #define MAIN_STK_SIZE 		128
    //任务控制块
    OS_TCB Main_TaskTCB;
    //任务堆栈	
    CPU_STK MAIN_TASK_STK[MAIN_STK_SIZE];
    //任务函数
    void main_task(void *p_arg);
    
    //任务优先级
    #define MEMMANAGE_TASK_PRIO	5
    //任务堆栈大小
    #define MEMMANAGE_STK_SIZE	128
    //任务控制块
    OS_TCB	MemManage_TaskTCB;
    //任务堆栈
    CPU_STK MEMMANAGE_TASK_STK[MEMMANAGE_STK_SIZE];
    //任务函数
    void memmanage_task(void *p_arg);
    
    //定义一个存储区
    OS_MEM INTERNAL_MEM;	
    //存储区中存储块数量
    #define INTERNAL_MEM_NUM		5
    //每个存储块大小
    //由于一个指针变量占用4字节所以块的大小一定要为4的倍数
    //而且必须大于一个指针变量(4字节)占用的空间,否则的话存储块创建不成功
    #define INTERNAL_MEMBLOCK_SIZE	25*4  
    //存储区的内存池,使用内部RAM
    __align(4) CPU_INT08U Internal_RamMemp[INTERNAL_MEM_NUM][INTERNAL_MEMBLOCK_SIZE];
    
    //定义一个存储区
    OS_MEM EXTERNAL_MEM;	
    //存储区中存储块数量
    #define EXTRENNAL_MEM_NUM		5
    //每个存储块大小
    //由于一个指针变量占用4字节所以块的大小一定要为4的倍数
    //而且必须大于一个指针变量(4字节)占用的空间,否则的话存储块创建不成功
    #define EXTERNAL_MEMBLOCK_SIZE	25*4
    //存储区的内存池,使用外部SRAM
    __align(32) volatile CPU_INT08U External_RamMemp[EXTRENNAL_MEM_NUM][EXTERNAL_MEMBLOCK_SIZE]  __attribute__((at(0X68000000)));	
    
    					
    void ucos_load_main_ui(void)                         //加载主界面
    {
    	POINT_COLOR = RED;
    	LCD_ShowString(30,10,200,16,16,"ALIENREK STM32F1");	
    	LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 14-1");
    	LCD_ShowString(30,50,200,16,16,"Memory Manage");
    	POINT_COLOR = BLUE;
    	LCD_ShowString(30,70,200,16,16,"INTERNAL_MEM:");
    	POINT_COLOR = RED;
    	LCD_ShowString(30,90,200,16,16,"KEY_UP:malloc KEY1:free");
    	POINT_COLOR = BLUE;
    	LCD_ShowString(30,110,200,16,16,"EXTERNAL_MEM:");
    	POINT_COLOR = RED;
    	LCD_ShowString(30,130,200,16,16,"KEY2:malloc KEY0:free");
    	POINT_COLOR = BLACK;
    	LCD_DrawLine(0,147,239,147);
    	POINT_COLOR = BLUE;
    	LCD_ShowString(5,148,200,16,16,"INTERNAL_MEM:");
    	LCD_ShowString(5,228,200,16,16,"EXTERNAL_MEM:");
    	POINT_COLOR = RED; 
    }
    
    int main(void)                            //主函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	delay_init();  //时钟初始化
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
    	uart_init(115200);   //串口初始化
    	LED_Init();         //LED初始化	
    	LCD_Init();			//LCD初始化	
    	KEY_Init();			//按键初始化
    	BEEP_Init();		//初始化蜂鸣器
    	FSMC_SRAM_Init();	//初始化SRAM
    	ucos_load_main_ui();//加载主UI1
    	
    	OSInit(&err);		    //初始化UCOSIII
    	OS_CRITICAL_ENTER();	//进入临界区	
    
    	OSMemCreate((OS_MEM*	)&INTERNAL_MEM,                    	//创建一个存储分区
    				(CPU_CHAR*	)"Internal Mem",
    				(void*		)&Internal_RamMemp[0][0],
    				(OS_MEM_QTY	)INTERNAL_MEM_NUM,
    				(OS_MEM_SIZE)INTERNAL_MEMBLOCK_SIZE,
    				(OS_ERR*	)&err);
    
    	OSMemCreate((OS_MEM*	)&EXTERNAL_MEM,                        	//创建一个存储分区
    				(CPU_CHAR*	)"External Mem",
    				(void*		)&External_RamMemp[0][0],
    				(OS_MEM_QTY	)EXTRENNAL_MEM_NUM,
    				(OS_MEM_SIZE)EXTERNAL_MEMBLOCK_SIZE,
    				(OS_ERR*	)&err);
    	//创建开始任务
    	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
    				 (CPU_CHAR	* )"start task", 		//任务名字
                     (OS_TASK_PTR )start_task, 			//任务函数
                     (void		* )0,					//传递给任务函数的参数
                     (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                     (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                     (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                     (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                     (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                     (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                     (void   	* )0,					//用户补充的存储区
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                     (OS_ERR 	* )&err);				//存放该函数错误时的返回值
    	OS_CRITICAL_EXIT();	//退出临界区	 
    	OSStart(&err);      //开启UCOSIII
    }
    
    void start_task(void *p_arg)                        //开始任务函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	p_arg = p_arg;
    	
    	CPU_Init();
    #if OS_CFG_STAT_TASK_EN > 0u
       OSStatTaskCPUUsageInit(&err);  	//统计任务                
    #endif
    	
    #ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
        CPU_IntDisMeasMaxCurReset();	
    #endif
    	
    #if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
    	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
    	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
    #endif	
    		
    	OS_CRITICAL_ENTER();	//进入临界区
    	//创建主任务
    	OSTaskCreate((OS_TCB*     )&Main_TaskTCB,		
    				 (CPU_CHAR*   )"Main task", 		
                     (OS_TASK_PTR )main_task, 			
                     (void*       )0,					
                     (OS_PRIO	  )MAIN_TASK_PRIO,     
                     (CPU_STK*    )&MAIN_TASK_STK[0],	
                     (CPU_STK_SIZE)MAIN_STK_SIZE/10,	
                     (CPU_STK_SIZE)MAIN_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void*       )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR*     )&err);
    	//创建一个内存块检查任务
    	OSTaskCreate((OS_TCB*     )&MemManage_TaskTCB,		
    				 (CPU_CHAR*   )"MemManage task", 		
                     (OS_TASK_PTR )memmanage_task, 			
                     (void*       )0,					
                     (OS_PRIO	  )MEMMANAGE_TASK_PRIO,     
                     (CPU_STK*    )&MEMMANAGE_TASK_STK[0],	
                     (CPU_STK_SIZE)MEMMANAGE_STK_SIZE/10,	
                     (CPU_STK_SIZE)MEMMANAGE_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void*       )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR*     )&err);
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void main_task(void *p_arg)                    //主任务的任务函数
    {
    	u8 key,num;
    	static u8 internal_memget_num;
    	static u8 external_memget_num;
    	CPU_INT08U *internal_buf;
    	CPU_INT08U *external_buf;
    	OS_ERR err;
    	while(1)
    	{
    		key = KEY_Scan(0);  //扫描按键
    		switch(key)
    		{
    			case WKUP_PRES:		//按下KEY_UP键
    				internal_buf=OSMemGet((OS_MEM*)&INTERNAL_MEM,
    								      (OS_ERR*)&err);
    				if(err == OS_ERR_NONE) //内存申请成功
    				{
    					printf("internal_buf内存申请之后的地址为:%#x\r\n",(u32)(internal_buf));
    					LCD_ShowString(30,180,200,16,16,"Memory Get success!  ");
    					internal_memget_num++;
    					POINT_COLOR = BLUE;
    					sprintf((char*)internal_buf,"INTERNAL_MEM Use %d times",internal_memget_num);
    					LCD_ShowString(30,196,200,16,16,internal_buf); 
    					POINT_COLOR = RED;
    				}
    				if(err == OS_ERR_MEM_NO_FREE_BLKS) //内存块不足
    				{
    					LCD_ShowString(30,180,200,16,16,"INTERNAL_MEM Empty!  ");
    				}
    				break;
    			case KEY1_PRES:
    				if(internal_buf != NULL) //internal_buf不为空就释放内存
    				{
    					OSMemPut((OS_MEM*	)&INTERNAL_MEM,		//释放内存
    							 (void*		)internal_buf,
    							 (OS_ERR* 	)&err);
    					printf("internal_buf内存释放之后的地址为:%#x\r\n",(u32)(internal_buf));
    					LCD_ShowString(30,180,200,16,16,"Memory Put success!   ");
    				}
    				break;
    			case KEY2_PRES:
    				external_buf=OSMemGet((OS_MEM*)&EXTERNAL_MEM,
    									  (OS_ERR*)&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((OS_MEM*	)&EXTERNAL_MEM,		//释放内存
    							 (void*		)external_buf,
    							 (OS_ERR* 	)&err);
    					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;
    		}
    		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms
    	}
    }
    
    void memmanage_task(void *p_arg)                    //内存管理任务
    {
    	OS_ERR err;
    	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.NbrMax,1,16,0);	
    		LCD_ShowxNum(125,164,INTERNAL_MEM.NbrFree,1,16,0);	
    		LCD_ShowxNum(53,244,EXTERNAL_MEM.NbrMax,1,16,0);	
    		LCD_ShowxNum(125,244,EXTERNAL_MEM.NbrFree,1,16,0);	
    		POINT_COLOR = RED;
    		OSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_PERIODIC,&err);//延时100ms
    	}
    }
    	//创建一个存储分区
    				(CPU_CHAR*	)"Internal Mem",
    				(void*		)&Internal_RamMemp[0][0],
    				(OS_MEM_QTY	)INTERNAL_MEM_NUM,
    				(OS_MEM_SIZE)INTERNAL_MEMBLOCK_SIZE,
    				(OS_ERR*	)&err);
    
    	OSMemCreate((OS_MEM*	)&EXTERNAL_MEM,                        	//创建一个存储分区
    				(CPU_CHAR*	)"External Mem",
    				(void*		)&External_RamMemp[0][0],
    				(OS_MEM_QTY	)EXTRENNAL_MEM_NUM,
    				(OS_MEM_SIZE)EXTERNAL_MEMBLOCK_SIZE,
    				(OS_ERR*	)&err);
    	//创建开始任务
    	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
    				 (CPU_CHAR	* )"start task", 		//任务名字
                     (OS_TASK_PTR )start_task, 			//任务函数
                     (void		* )0,					//传递给任务函数的参数
                     (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                     (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                     (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                     (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                     (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                     (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                     (void   	* )0,					//用户补充的存储区
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                     (OS_ERR 	* )&err);				//存放该函数错误时的返回值
    	OS_CRITICAL_EXIT();	//退出临界区	 
    	OSStart(&err);      //开启UCOSIII
    }
    
    void start_task(void *p_arg)                        //开始任务函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	p_arg = p_arg;
    	
    	CPU_Init();
    #if OS_CFG_STAT_TASK_EN > 0u
       OSStatTaskCPUUsageInit(&err);  	//统计任务                
    #endif
    	
    #ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
        CPU_IntDisMeasMaxCurReset();	
    #endif
    	
    #if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
    	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
    	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
    #endif	
    		
    	OS_CRITICAL_ENTER();	//进入临界区
    	//创建主任务
    	OSTaskCreate((OS_TCB*     )&Main_TaskTCB,		
    				 (CPU_CHAR*   )"Main task", 		
                     (OS_TASK_PTR )main_task, 			
                     (void*       )0,					
                     (OS_PRIO	  )MAIN_TASK_PRIO,     
                     (CPU_STK*    )&MAIN_TASK_STK[0],	
                     (CPU_STK_SIZE)MAIN_STK_SIZE/10,	
                     (CPU_STK_SIZE)MAIN_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void*       )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR*     )&err);
    	//创建一个内存块检查任务
    	OSTaskCreate((OS_TCB*     )&MemManage_TaskTCB,		
    				 (CPU_CHAR*   )"MemManage task", 		
                     (OS_TASK_PTR )memmanage_task, 			
                     (void*       )0,					
                     (OS_PRIO	  )MEMMANAGE_TASK_PRIO,     
                     (CPU_STK*    )&MEMMANAGE_TASK_STK[0],	
                     (CPU_STK_SIZE)MEMMANAGE_STK_SIZE/10,	
                     (CPU_STK_SIZE)MEMMANAGE_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void*       )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR*     )&err);
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void main_task(void *p_arg)                    //主任务的任务函数
    {
    	u8 key,num;
    	static u8 internal_memget_num;
    	static u8 external_memget_num;
    	CPU_INT08U *internal_buf;
    	CPU_INT08U *external_buf;
    	OS_ERR err;
    	while(1)
    	{
    		key = KEY_Scan(0);  //扫描按键
    		switch(key)
    		{
    			case WKUP_PRES:		//按下KEY_UP键
    				internal_buf=OSMemGet((OS_MEM*)&INTERNAL_MEM,
    								      (OS_ERR*)&err);
    				if(err == OS_ERR_NONE) //内存申请成功
    				{
    					printf("internal_buf内存申请之后的地址为:%#x\r\n",(u32)(internal_buf));
    					LCD_ShowString(30,180,200,16,16,"Memory Get success!  ");
    					internal_memget_num++;
    					POINT_COLOR = BLUE;
    					sprintf((char*)internal_buf,"INTERNAL_MEM Use %d times",internal_memget_num);
    					LCD_ShowString(30,196,200,16,16,internal_buf); 
    					POINT_COLOR = RED;
    				}
    				if(err == OS_ERR_MEM_NO_FREE_BLKS) //内存块不足
    				{
    					LCD_ShowString(30,180,200,16,16,"INTERNAL_MEM Empty!  ");
    				}
    				break;
    			case KEY1_PRES:
    				if(internal_buf != NULL) //internal_buf不为空就释放内存
    				{
    					OSMemPut((OS_MEM*	)&INTERNAL_MEM,		//释放内存
    							 (void*		)internal_buf,
    							 (OS_ERR* 	)&err);
    					printf("internal_buf内存释放之后的地址为:%#x\r\n",(u32)(internal_buf));
    					LCD_ShowString(30,180,200,16,16,"Memory Put success!   ");
    				}
    				break;
    			case KEY2_PRES:
    				external_buf=OSMemGet((OS_MEM*)&EXTERNAL_MEM,
    									  (OS_ERR*)&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((OS_MEM*	)&EXTERNAL_MEM,		//释放内存
    							 (void*		)external_buf,
    							 (OS_ERR* 	)&err);
    					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;
    		}
    		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms
    	}
    }
    
    void memmanage_task(void *p_arg)                    //内存管理任务
    {
    	OS_ERR err;
    	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.NbrMax,1,16,0);	
    		LCD_ShowxNum(125,164,INTERNAL_MEM.NbrFree,1,16,0);	
    		LCD_ShowxNum(53,244,EXTERNAL_MEM.NbrMax,1,16,0);	
    		LCD_ShowxNum(125,244,EXTERNAL_MEM.NbrFree,1,16,0);	
    		POINT_COLOR = RED;
    		OSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_PERIODIC,&err);//延时100ms
    	}
    }

     

    展开全文
  • UCOSIII存储管理

    2018-12-16 19:04:54
    1.1、存储管理: 作为一个RTOS操作系统,内存管理是必备的功能,因此UCOSIII也有内存管理能力。通常应用程序可以调用ANSI C编译器malloc()和free()函数来动态分配和释放内存,但是在嵌入式事实操作系统中最好...

    1.1、存储管理:

    作为一个RTOS操作系统,内存管理是必备的功能,因此UCOSIII也有内存管理能力。通常应用程序可以调用ANSI C编译器的malloc()和free()函数来动态的分配和释放内存,但是在嵌入式事实操作系统中最好不要这么做,多次这样的操作会把原来很大的一块连续存储区域逐渐地分割成许多非常小并且彼此不相邻的存储区域,这就是存储碎片。

    UCOSIII中提供了一种替代malloc()和free()函数的方法,UCOSIII中将存储空间分成区和块,每个存储区有数量不等大小相同的存储块,在一个系统中可以有多个存储区。一般存储区是固定的,在程序中可以用数组来表示一个存储区,比如u8 buffer[20][10],就表示一个拥有20个存储块,每个存储块10个字节的存储区。

    1.2、存储控制块:

    UCOSIII中用存储控制块来表示存储区,存储控制块为OS_MEM。

    struct os_mem {

    OS_OBJ_TYPE          Type;

    void                  *AddrPtr;

    CPU_CHAR            *NamePtr;

    void                  *FreeListPtr;

    OS_MEM_SIZE          BlkSize;

    OS_MEM_QTY          NbrMax;

    OS_MEM_QTY          NbrFree;

    #if OS_CFG_DBG_EN > 0u

        OS_MEM          *DbgPrevPtr;

        OS_MEM          *DbgNextPtr;

    #endif

    };

    创建好的存储区如下图

    2.1、存储管理相关API函数:

    OSMemCreate()   创建一个存储分区

    OSMemGet()     从存储分区中获得一个存储块

    OSMemPut()     将一个存储块归还到存储分区中

    展开全文
  • 第十四章 存储管理

    2021-02-18 20:24:12
    作为一个操作系统,内存管理是其必备的功能,在 UCOSIII中也有内存管理模块,使用内 存管理模块可以动态分配和释放内存,这样可以高效使用“昂贵”内存资源,本章我们 ...14.4存储管理实验 ...

    作为一个操作系统,内存管理是其必备的功能,在 UCOSIII中也有内存管理模块,使用内
    存管理模块可以动态的分配和释放内存,这样可以高效的使用“昂贵”的内存资源,本章我们
    就学习一下 UCOSIII的内存管理,本章分为如下几部分:
    14.1内存管理简介
    14.2存储区创建
    14.3存储块的使用
    14.4存储管理实验

    展开全文
  • 第3章 存储管理

    2016-06-17 14:40:47
    内存管理的功能 分配和回收 地址转换 内存空间的扩充 存储保护 2. 地址重定位 逻辑地址空间 物理地址空间 地址重地位 重定位类型重定位寄存器 将逻辑地址与重定位寄存器中的内容相加后得到的地址作为访问内存的地址...

    第3章 存储管理


    3.1 内存管理基础

    3.1.1 内存管理概念

    1. 内存管理的功能

    • 分配和回收
    • 地址转换
    • 内存空间的扩充
    • 存储保护

    2. 地址重定位

    1. 逻辑地址空间
    2. 物理地址空间
    3. 地址重地位
    4. 重定位类型
    重定位寄存器
    将逻辑地址与重定位寄存器中的内容相加后得到的地址作为访问内存的地址

    3. 链接


    3.1.2 交换与覆盖

    交换
    让出处理机,释放占用的内存
    覆盖
    轮流使用某段存储空间

    3.1.3 存储分配方式

    3.1.4 连续分配管理方式

    • 首次适应算法Frist Fit
    • 下次适应算法Next Fit
    • 最佳适应算法Best Fit
    • 最坏适应算法Worst Fit

    3.1.5 非连续分配管理方式

    1. 简单分页存储管理

    1. 等分内存:存储块 = 页框
    2. 【逻辑地址】分页:页面 = 页
    3. 逻辑地址的表示:(p, d) p是页号,d是相对地址
    4. 内存分配原则:
    5. 页表与页表地址寄存器

    这里写图片描述

    这里写图片描述
    页表和页表地址寄存器

    页面和物理块
    分页存储管理是将一个进程的逻辑地址空间分成若干个大小相等的片称为页面或页,并为各页加以编号,从0开始。同时把内存空间分成与页面相同大小的若干个存储块,称为或页框。在为进程分配内存时,以块为单位将进程的若干个页分别装入到多个可以不相邻的物理块中。
    页表
    一组重定位寄存器,页表实现了从页号到物理块号的地址映射,它的起始地址和大小保存在该作业的PCB中。在系统中只设置一个页表寄存器PTR,在其中存放页表在内存中的始址和页表的长度。
    快表
    寄存器,页号块号
    地址结构
    地址长度32位:
    0~11位为位移量(页内地址),即每页的大小为4KB
    12~31位为页号,地址空间最多允许有1M页

    两级页表
    32位逻辑地址空间,页面大小为4KB(即12位),每个页表项占4个字节,若采用一级页表机构,应有20位页号,即页表项应有1M个;在采用两级页表机构时,再对页表进行分页,使每页包含210(即1024)个页表项,最多允许有210个页表分页。即

    这里写图片描述

    2. 分段存储管理

    自然段
    代码段,数据段,堆栈段
    二维地址结构
    段号s和段内相对地址w

    分段系统的地址结构如图:
    这里写图片描述

    该地址结构允许一个作业最长有64K个段,每段的最大长度为64KB。因此,用户在程序设计时,每个段的最大长度受到地址结构的限制。进一步,每一个程序中允许的最多段数也受到限制。

    3. 段页式管理

    三次访问内存
    段号,页号,指令或数据

    3.2 虚拟存储管理

    3.2.1 虚拟存储器基本概念

    虚拟存储器定义
    是指具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器

    1.请求分页系统
    2.请求分段系统

    1. 局部性原理

    2. 虚拟存储

    3. 实现虚拟存储的基础

    硬件基础 软件基础
    一定的存储容量 页表段表
    大容量的外存 中断服务程序
    缺页中断机构 操作系统支持

    硬件支持:①请求分页的页表机制 ②缺页中断机构 ③地址变换机构
    软件支持:实现请求调页的软件和实现页面置换的软件

    4. 虚拟存储的主要特征

    • 离散性
    • 多次性
    • 对换性
    • 虚拟性

    3.2.2 请求分页管理方式

    1. 请求分页的基本原理
    2. 页表的扩充
    3. 地址变换
    4. 缺页中断处理
    5. 调页策略

    这里写图片描述

    3.2.3 页面置换算法

    • 随机淘汰算法
    • 先进先出算法
    • 最佳置换算法
    • 最近最久未使用页面置换算法

    3.2.4 页面分配策略

    3.2.5 工作集

    工作集
    频率非常高的页面置换现象
    展开全文
  • 存储管理是指主存管理(外存管理见文件系统),包括给进程分配主存片段,收回进程释放的主存片段,为分配出去主存片段提供保护与共享,以及为作业提供一个虚拟存储空间。  主要功能:分配,回收,保护,共享,...
  • 设计内容: (1)采用空白文件目录结构管理磁盘空间,实现磁盘空间...(3)把个文件目录、磁盘空间管理的数据结构变化情况显示出来。 三个功能应该都有,我负责的是空白文件目录结构管理磁盘空间,采用的是队列的方式
  • 通过编写固定分区存储管理的模拟程序,加深对操作系统存储管理功能中的固定分区管理方式、主存分配表等相应知识的理解。 二、实验内容 1、实现固定分区存储管理方式下存储空间的分配和去配。 2、已知当前内存分配表...
  • 仿真连续分配存储管理系统,至少包括以下功能:并发分配与回收、查询、拼接等功能。 在动态分区管理系统中,主要操作是分配内存和回收内存。 分配内存:系统利用某种分配算法,从空闲分区链(表)中找到所需大小...
  • 系统区:当系统初始化启动时候,操作系统内核将自己代码和静态数据结构加载到主存底端,这部分存储空间不能被修改、不再释放、不被覆盖。 用户区:在系统初始化结束之后,操作系统开始对其余空间进行动态管理...
  • 5. C语言动态存储管理机制;例;malloc说明;6. calloc;7. 空间释放函数free;8. 分配调整函数realloc;二动态存储空间管理;方法1指针数组地址数组;例如;指针数组结构示例;功能实现;功能实现续;功能示例;功能实现续;
  • 2018.12.12;...5. C语言动态存储管理机制;例;malloc说明;6. calloc;7. 空间释放函数free;8. 分配调整函数realloc;二动态存储空间管理;方法1指针数组地址数组;例如;指针数组结构示例;功能实现;功能实现续;
  • 内存管理的问题包括:内存管理方法、内存的分配和释放算法、虚拟存储器的管理、控制内存和外存之间的数据流动方法、地址变换技术和内存数据保护与共享技术等。2、内存的分配和管理:该功能必须要记住每个存储区域的...
  • 可变分区存储管理-循环首次适应法摘要算法思想和概要设计算法思想分配算法释放算法概要设计初始化分配释放数据结构与变量说明双向链表表项:全局指针源程序链表结构体与全局变量定义循环首次适应法分配函数...
  • 作为一个操作系统,内存管理是其必备的功能,在UCOSIII中也有内存管理模块,使用内存管理模块可以动态分配和释放内存,这样可以高效使用“昂贵”内存资源,本章讲解一下UCOSIII内存管理。 1、存储管理简介 ...
  • Microsoft® Exchange Server 分析工具查询 Active Directory® 目录服务,以确定每个邮箱存储的 garbageCollPeriod 属性值。如果 Exchange Server ...垃圾收集是 Exchange 一个内部维护管理过程,可以释放邮箱存储
  • C语言在使用完内存够,需要程序员自己手动释放,但是其他不用,但是内存回收一定是存在 2、地址转换 逻辑地址到物理地址转换 逻辑地址:我们认为它在地址 物理地址:实际上在地址 3、内存空间扩充 虚拟...
  • 在控制台输入信息会自动记入到该文件中,缺点是无法对文件本身进行操作改变信息,优点是使用链表结构,可以存储数量未知学生信息 ,退出时会释放空间。 个人吐槽: emmmmm,累死我了,吐血之作,来个点赞收藏帮...
  • 也就是说,把存储功能从通用文件服务器中分离出来,使其更加专门化,从而释放带宽,获得更高存取效率,更低的存储成本,保护投资。。NAS设备近两年开始流行,可靠稳定性能、特别优化文件管理系统和低廉价格...
  • 今天继续学习,接着前一条...使用C语言接口最大问题是手工内存管理,需要手动分配和释放内存。OpenCV 2.0以后引进了C++接口,用户不用再纠结于内存管理,使代码更简洁明了(less to write, to achieve more)。...
  • 将图片存储在了七牛云服务器中。但是这个过程存在一个问题,就是如 果用户只上传了图片而没有最终保存套餐信息到我们数据库,这时我们上传图片就变为了垃圾图 片。对于这些垃圾图片我们需要定时清理来释放磁盘...
  • 仔细读读操作系统原理的资料以及系统内存管理的技术说明,swap或是win虚拟内存更多是被系统当成一种低速的cache使用,或者寄放长期不用的程序代码段在内存中释放空间做高速cache。总之强调一种缓存而不是内存功能。...
  • 它以数据为中心,将存储设备与服务器彻底分离,集中管理数据,从而释放带宽、提高性能、降低总拥有成本、保护投资。其成本远远低于使用服务器存储,而效率却远远高于后者。目前国际著名NAS企业有Netapp、EMC、OUO...
  • 这是一种便捷方式来释放Kubernetes中动态预配置持久性GlusterFS卷的功能。 组成项目 ,容器管理系统。 ,横向扩展存储系统。 ,GlusterFSRESTful卷管理接口。 简报 您可以找到社区演示幻灯片和视频。 >...
  • 问题一什么叫垃圾回收机制垃圾回收是一种动态存储管理技术它自动地释放不再被程序引用对象按照特定垃圾收集算法来实现资源自动回收的功能。当一个对象不再被引用时候内存回收它占领空间以便...
  • NAS(Network Attached Storage:网络附属存储)是一种将分布、独立的数据整合为大型、集中化管理的数据中心,以便于对不同主机和应用服务器进行访问的技术。按字面简单说就是连接在网络上, 具备资料存储功能的装置...
  • NanoSupport WordPress智能支持票务插件 需要 经过测试 稳定释放 w.org评分 执照 w.org下载 WordPress 4.4.0 介绍 在您WordPress环境中创建功能全面... 因此,该插件仅在您和您特定客户之间提供私密管理通信
  • 垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用对象,按照特定垃圾收集算法来实现资源自动回收的功能。当一个对象不再被引用时候,内存回收它占领空间,以便空间被后来新对象使用,以免造成...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 561
精华内容 224
关键字:

存储管理的释放功能