动态内存管理本章主要讲述:基本概念建立一个内存分区分配一个内存块释放一个内存块基本概念应用程序在运行中经常需要临时获得一些内存空间,用完后需要归还这些内存空间。能否合理、有效地对内存储器进行分配和管理,是衡量一个操作系统的指标之一。特别地对于实时操作系统来说,还应该保证系统在动态分配内存时,它的执行时间必须是可确定的。μC/OS-II对内存进行两级管理:①把一个大片连续的内存空间分成了若干个内存分区②每个分区又分成了若干个大小相等的内存块任务以内存块为单位来获得和释放动态内存。每个内存分区及其内存块的使用情况则由表——内存控制块来记录。创建内存分区前后应用程序如果要使用动态内存的话,则要首先在内存中划分出可以进行动态分配的区域,这个划分出来区域叫做内存分区,每个分区要包含若干个内存块(μC/OS-II要求同一个分区中的内存块的大小必须相等)。在内存中划分一个内存分区与内存块的方法非常简单:先定义一个二维数组,然后基于这个二维数组创建一个内存分区就可以了(其中每个一维数组,即二维数组的一个元素(一行),就是一个内存块)。示例OS_MEM*PartitionPtr;INT16UMemBuf[100][10];PartitionPtr=OSMemCreate(Partition,100,10,&err);上述语句定义了一个内存分区,它有100个内存块,每个内存块的大小为20个字节。并建立一个把内存控制块与内存分区关联起来,以便系统能对其进行相应的管理和控制。内存控制块为了使系统能够感知和有效地管理内存分区,μC/OS-II给每个内存分区定义了一个叫做内存控制块(OS_MEM)的数据结构。系统就用这个内存控制块来记录和跟踪每一个内存分区的状态。并通过它来申请和释放内存块。内存控制块的结构typedefstruct{void*OSMemAddr;//内存分区的指针void*OSMemFreeList;//内存控制块链表的指针INT32UOSMemBlkSize;//内存块的长度INT32UOSMemNBlks;//分区内内存块的数目INT32UOSMemNFree;//分区内当前可分配的内存块的数目}OS_MEM;系统初始化时创建的空内存控制块链表创建一个内存分区在使用一个内存分区之前,必须先建立一个内存分区。通过一个二维数组划分了欲使用的分区和内存块之后,应用程序可以通过OSMemCreate()建立一个内存分区。OS_MEM*OSMemCreate(void*addr,//内存分区的起始地址INT32Unblks,//分区中内存块的数目INT32Ublksize,//每个内存块的字节数INT8U*err//错误信息);创建内存分区前后申请一个内存块在应用程序需要一个内存块时,应用程序可以通过调用函数OSMemGet()向某内存分区请求获得一个内存块,OSMemGet()函数的原型为:void*OSMemGet(OS_MEM*pmem,//内存分区的指针INT8U*err//错误信息);释放一个内存块当应用程序不再使用一个内存块时,必须及时地将它释放。应用程序通过调用函数OSMemPut()来释放一个内存块,OSMemPut()函数原型为:INT8UOSMemPut(OS_MEM*pmem,//内存块所属内存分区的指针void*pblk//待释放内存块的指针);内存管理的应用-消息队列创建一个内存分区,用该内存分区存放消息队列的消息内容内存分区的每一个内存块存放一条消息的内容。INT32UTimes;//定义用户任务MyTask、YourTask的堆栈OS_STKMyTaskStk[TaskStkSize];OS_STKYourTaskStk[TaskStkSize];OS_EVENT*MsgQueue;//定义消息队列指针void*MsgQueueTbl[MAX_MESSAGES];//定义消息指针数组INT8UPartition[MAX_MESSAGES][MESSAGE_SIZE];OS_MEM*PartitionPtr;//定义内存分区指针voidMyTask(void*pdata);voidYourTask(void*pdata);intmain(intargc,char**argv){INT8Uerr;OSInit();OSTaskCreate(MyTask,0,&MyTaskStk[TaskStkSize-1],6);OSTaskCreate(YourTask,0,&YourTaskStk[TaskStkSize-1],5);//创建内存分区,用于保存消息PartitionPtr=OSMemCreate(Partition,MAX_MESSAGES,MESSAGE_SIZE,&err);//创建消息队列MsgQueue=OSQCreate(&MsgQueueTbl[0],MAX_MESSAGES);OSStart();return0;}voidMyTask(void*pdata){//生产者任务INT8Uerr,n=0;char*pt;pdata=pdata;while(1){Times++;printf(我是任务MyTask!已经运行%d次\n,Times);pt=OSMemGet(PartitionPtr,&err);//申请一个内存块存放消息sprintf(pt,MyTask运行次数:%d,Times);OSQPost(MsgQueue,pt);//pt为指向消息的指针,将该指针放到消息队列中n=(n+1)%10;OSTimeDlyHMSM(0,0,ProduceDelay[n],0);}}voidYourTask(void*pdata){//消费者任务INT8Uerr,m=0;char*pt;pdata=pdata;while(1){pt=(char*)OSQPend(MsgQueue,0,&err);//从邮箱中获得指向消息内容的指针ssif(err==OS_NO_ERR){printf(收到MyTask发来的消息:%s\n,pt);printf(任务YourTask:我来唱首歌!\n);…….}OSMemPut(PartitionPtr,pt);m=(m+1)%10;OSTimeDlyHMSM(0,0,ConsumeDelay[m],0);}}