uCOSii内存管理

uCOSii内存管理(MEMORY MANAGEMENT)

OSMemGet()执行一次,只能申请一个节点,由于节点的数据长度是固定的,所以可用内存的长度是固定的,这一点和malloc()不同

OSMemPut()执行一次,只释放一个节点,这一点和free()用法差不多,不用关心内存的长度,只要知道内存首地址就可以释放内存。

内存碎片,就是"可用的节点"被"已用的节点"分成多个、互不相连的小数据块。这时,若我们再想申请很大的内存,就不可能了。而uCOSii规避了这个问题,因为申请一次内存最多也就是一个节点,不允许你申请更多的节点,所以,就没有碎片之说。也就是说,即使"可用的节点"被"已用的节点"分成多个、互不相连的小数据块,你也只能申请一个节点,所以这种担心是多余的。所以uCOSii可以随时释放,不作要求,不分先后,因为它没有内存碎片之说。但释放内存还是按照"先申请后释放"原则,要养成习惯

注意:在uCOSii中,可用的节点含有指针域,一旦该节点被使用了,指针域变成了数据域的一部分。这和其他系统可能不一样。

由于节点的大小是固定的,可以创建不同的链表,供系统使用,节点最小为4个字节。

当指针为4字节时,链表必须是以4字节对齐的数据块,它是由一系列节点组成的;

每个节点也是一个以4字节对齐的数据块,我们叫它小数据块或叫节点;

这个小数据块分为两个部分:

一部分是存储下一个节点地址的指针域,另外一部分是存储数据的数据域;

链表的节点可能是连续的,但也可能是离散的;

链表的第一个节点,称为根节点,通过它可以找到其他节点中的数据;

uCOSii中使用的是单向链表,最后一个节点的指针域是空的;

数组是通过开辟一段连续的内存来存储数据,它的每个元素和链表中的节点相对应;

由于数组是连续的数据块,因此指针不用保存,每个元素是一个数据域;

#define NumberOfMyNodes         10  //存储区中存储块数量"节点数量"

#define SizeOfMyNode    4          //每个存储块大小为4,即节点的大小为4

//由于一个指针变量占用4字节所以块的大小一定要为4的倍数

//而且必须大于等于一个指针变量(4字节)占用的空间,否则的话存储块创建不成功

//STM32F10xxx内置64K字节的静态SRAM,它可以以字节,半字(16位)或全字(32位)访问

//SRAM的起始地址是0x20000000

__align(4) u8 MyChainTable[NumberOfMyNodes][SizeOfMyNode] __attribute__((at(0x20001000)));

//定义一个数组,用作链表

typedef struct os_mem

{

    void   *OSMemAddr;   /*根节点地址*/

    void   *OSMemFreeList;/*下一个节点的地址*/

    INT32U  OSMemBlkSize;/*节点的字节数*/

    INT32U  OSMemNBlks; /*节点的总数量”*/

    INT32U  OSMemNFree;/*可用节点数量*/

#if OS_MEM_NAME_EN > 0u

    INT8U  *OSMemName; /*指向链表名字的指针*/

#endif

}OS_MEM;

OS_MEM *OSMemFreeList;

//函数功能:将addr[nblks][ blksize]生成链表,并将链表地址返回

//addr根节点地址

//nblks节点的总数量

//blksize节点的字节数

OS_MEM  *OSMemCreate (void *addr,INT32U  nblks,INT32U blksize,INT8U *perr)

{

    OS_MEM    *pmem;

    INT8U     *pblk;

    void     **plink;

    INT32U     loops;

    INT32U     i;

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

///检查开始

#ifdef OS_SAFETY_CRITICAL

if (perr == (INT8U *)0)

{//perr指针为0

        OS_SAFETY_CRITICAL_EXCEPTION();

    }

#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508

if (OSSafetyCriticalStartFlag == OS_TRUE)

{

        OS_SAFETY_CRITICAL_EXCEPTION();

    }

#endif

#if OS_ARG_CHK_EN > 0u

if (addr == (void *)0)

{//检查到连续存储块的首地址为0

        *perr = OS_ERR_MEM_INVALID_ADDR;

        return ((OS_MEM *)0);

}

if ( (  (INT32U)addr  &  ( sizeof(void *) - 1u)  ) != 0u )

{//sizeof(void *)=4,则addr不满足4字节对齐

        *perr = OS_ERR_MEM_INVALID_ADDR;

        return ((OS_MEM *)0);

}

if (nblks < 2u)

    {//”节点的总数量至少是2,否则链表没有意义

        *perr = OS_ERR_MEM_INVALID_BLKS;

        return ((OS_MEM *)0);

}

if (blksize < sizeof(void *))

{//节点是由指针域和数据域组成;

 //sizeof(void *)=4,则节点字节数必须大于等于4

    *perr = OS_ERR_MEM_INVALID_SIZE;

        return ((OS_MEM *)0);

    }

#endif

OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

pmem = OSMemFreeList;

//因为他们都是指针,修改pmem就等同修改OSMemFreeList

// OSMemFreeListuCOSii创建的OS_MEM结构指针

if (OSMemFreeList != (OS_MEM *)0)

{//查看系统是否声明过” OSMemFreeList结构指针变量

       OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;

       //下一个节点的地址

    }

OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

if (pmem == (OS_MEM *)0)

{//检查到pmem结构指针为0

        *perr = OS_ERR_MEM_INVALID_PART;

        return ((OS_MEM *)0);

}

///检查结束

plink = (void **)addr;

// addr根节点地址

//plinkvoid**型指针的指针, plink指针赋值

pblk = (INT8U *)addr;

// addr根节点地址

//pblk是字节型指针, pblk指针赋值

loops = nblks - 1u;

//nblks节点的总数量

for (i = 0u; i < loops; i++)

{

        pblk +=blksize;

        //blksize节点的字节数

//修改” pblk指针,使它指向下一个节点的首地址

       *plink = (void  *)pblk;

       //pblk是字节型指针,使用(void *)将该指针强制转换为void*型指针

       // plink为当前节点的首地址

       //当前节点的指针域赋值,记录下一个节点的首地址

        plink = (void **)pblk;

        //pblk是字节型指针,使用(void **)将该指针强制转换为void**型指针

//plink指针赋值, 使plink指向下一个节点的首地址

    }

*plink = (void *)0;

//最后一个节点的指针域赋值,记录下一个节点的首地址为0

pmem->OSMemAddr= addr;      //根节点地址

pmem->OSMemFreeList = addr;   //下一个节点的地址

pmem->OSMemNFree= nblks;     //可用节点数量

pmem->OSMemNBlks    = nblks; //节点的总数量

pmem->OSMemBlkSize  = blksize;//节点的字节数

    *per = OS_ERR_NONE;

    return (pmem);//返回pmem指针

}

//pmemOS_MEM结构指针,用来管理链表操作

//per=OS_ERR_NONE,表示申请到内存

//返回值为申请到节点的首地址,不等于0,表示申请到一个节点

//注意:OSMemGet()执行一次,只能申请一个节点

//由于节点的数据长度是固定的,这一点和malloc()不同

//ptr=OSMemGet(INTERNAL_MEM_Pointer,&err);

void  *OSMemGet (OS_MEM  *pmem,INT8U   *perr)

{

    void      *pblk;

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#ifdef OS_SAFETY_CRITICAL

if (perr == (INT8U *)0)

{//perr指针为0

        OS_SAFETY_CRITICAL_EXCEPTION();

    }

#endif

#if OS_ARG_CHK_EN > 0u

if (pmem == (OS_MEM *)0)

{//pmem指针为0

        *perr = OS_ERR_MEM_INVALID_PMEM;

        return ((void *)0);

    }

#endif

    OS_ENTER_CRITICAL();

if(pmem->OSMemNFree > 0u)

{//可用节点数量大于0

        pblk = pmem->OSMemFreeList;// 读取”下一个节点”的地址

        pmem->OSMemFreeList = *(void **)pblk;//读取”下下一个节点”的地址

        pmem->OSMemNFree--;//可用节点数量减1

        OS_EXIT_CRITICAL();

        *perr = OS_ERR_NONE;

        return (pblk); //申请到内存

}

//可用节点数量等于0//

OS_EXIT_CRITICAL();

    *perr = OS_ERR_MEM_NO_FREE_BLKS;

    return ((void *)0);//没有申请到内存

}

//函数功能:释放地址为pblk的数据块,使它再次变为可用的节点

//pmemOS_MEM结构指针,用来管理链表操作

//pblk为释放节点的首地址

//OSMemPut(INTERNAL_MEM_Pointer,ptr);

//注意: OSMemPut()执行一次,只释放一个节点

//这一点和free()用法差不多,只要知道内存首地址就可以释放内存;

//通常后申请的节点先释放,先申请的节点后释放

INT8U  OSMemPut (OS_MEM  *pmem, void *pblk)

{

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#if OS_ARG_CHK_EN > 0u

if (pmem == (OS_MEM *)0)

{//pmem指针为0

        return (OS_ERR_MEM_INVALID_PMEM);

    }

if (pblk == (void *)0)

{//pblk指针为0

        return (OS_ERR_MEM_INVALID_PBLK);

    }

#endif

    OS_ENTER_CRITICAL();

if (pmem->OSMemNFree >= pmem->OSMemNBlks)

{//pmem->OSMemNFree可用节点数量

 //pmem->OSMemNBlks节点的总数量

        OS_EXIT_CRITICAL();

        return (OS_ERR_MEM_FULL);

}

*(void **)pblk= pmem->OSMemFreeList;

//读取”下一个节点”的地址,用这个地址去覆盖当前释放节点的”指针域”

//将这个释放的块插入到”可用的节点”中间 

    pmem->OSMemFreeList = pblk;//更新”下一个节点”的地址

pmem->OSMemNFree++;        //可用节点数量加1

    OS_EXIT_CRITICAL();

return (OS_ERR_NONE);                       

}

typedef struct os_mem_data

{

void   *OSAddr; //根节点地址

void   *OSFreeList; //可用的下一个节点的地址               

INT32U  OSBlkSize; //节点的字节数

INT32U  OSNBlks; //节点的总数量

INT32U  OSNFree; //可用节点数量                  

INT32U  OSNUsed; //用的节点数量                 

}OS_MEM_DATA;

//pmemOS_MEM结构指针,用来管理链表操作

INT8U  OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *p_mem_data)

{

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#if OS_ARG_CHK_EN > 0u

if (pmem == (OS_MEM *)0)

{

        return (OS_ERR_MEM_INVALID_PMEM);

    }

if (p_mem_data == (OS_MEM_DATA *)0)

{

        return (OS_ERR_MEM_INVALID_PDATA);

    }

#endif

    OS_ENTER_CRITICAL();

    p_mem_data->OSAddr     = pmem->OSMemAddr;     //根节点地址

    p_mem_data->OSFreeList = pmem->OSMemFreeList; //可用的下一个节点的地址

    p_mem_data->OSBlkSize  = pmem->OSMemBlkSize;  //节点的字节数

    p_mem_data->OSNBlks    = pmem->OSMemNBlks;    //节点的总数量

    p_mem_data->OSNFree    = pmem->OSMemNFree;    //可用节点数量

OS_EXIT_CRITICAL();

p_mem_data->OSNUsed = p_mem_data->OSNBlks - p_mem_data->OSNFree;

//用的节点数量

    return (OS_ERR_NONE);

}

#include "MEMORY_Task.h"

#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "My_Task_Priority.h"

void PrintMyChainTable(void);

void MEMORY_Task(void *pdata);

const char MEMORY_Task_rn_REG[]="\r\n";

const char MEMORY_Task_Initialise_REG[]="MEMORY_Task Initialise";

/*

MyRootNode=0x20001000

AddressOfMyNodes=0x20001000,     AddressOfMyNextNode=0x20001020,     MyChainTable[0][0]=0x20001020

AddressOfMyNodes=0x20001020,     AddressOfMyNextNode=0x20001040,     MyChainTable[1][0]=0x20001040

AddressOfMyNodes=0x20001040,     AddressOfMyNextNode=0x20001060,     MyChainTable[2][0]=0x20001060

AddressOfMyNodes=0x20001060,     AddressOfMyNextNode=0x20001080,     MyChainTable[3][0]=0x20001080

AddressOfMyNodes=0x20001080,     AddressOfMyNextNode=0x200010a0,     MyChainTable[4][0]=0x200010a0

AddressOfMyNodes=0x200010a0,     AddressOfMyNextNode=0x200010c0,     MyChainTable[5][0]=0x200010c0

AddressOfMyNodes=0x200010c0,     AddressOfMyNextNode=0x200010e0,     MyChainTable[6][0]=0x200010e0

AddressOfMyNodes=0x200010e0,     AddressOfMyNextNode=0x20001100,     MyChainTable[7][0]=0x20001100

AddressOfMyNodes=0x20001100,     AddressOfMyNextNode=0x20001120,     MyChainTable[8][0]=0x20001120

AddressOfMyNodes=0x20001120,     AddressOfMyNextNode=0x0,     MyChainTable[9][0]=0x0

*/

void PrintMyChainTable(void)

{

    u32 i;

    u32 *p;

    printf("%s",MEMORY_Task_rn_REG);

    p=(u32*)&MyChainTable[0][0];

    printf("MyRootNode=0x%p",p);

    for (i=0;i

    {

        p=(u32*)&MyChainTable[i][0];

        printf("%s",MEMORY_Task_rn_REG);

        printf("AddressOfMyNodes=0x%p,     AddressOfMyNextNode=0x%x,     MyChainTable[%u][0]=0x%x",p,*p,i,*p);

    }

}

/*

执行测试结果如下:

Address_0x20001000=0x12345678     Address_0x20001004=0x87654321

MyRootNode=0x20001000

AddressOfMyNodes=0x20001000,     AddressOfMyNextNode=0x12345678,     MyChainTable[0][0]=0x12345678,占用指针域,保存数据

AddressOfMyNodes=0x20001004,     AddressOfMyNextNode=0x87654321,     MyChainTable[1][0]=0x87654321,占用指针域,保存数据

AddressOfMyNodes=0x20001008,     AddressOfMyNextNode=0x2000100c,     MyChainTable[2][0]=0x2000100c

AddressOfMyNodes=0x2000100c,     AddressOfMyNextNode=0x20001010,     MyChainTable[3][0]=0x20001010

AddressOfMyNodes=0x20001010,     AddressOfMyNextNode=0x0,     MyChainTable[4][0]=0x0

MyRootNode=0x20001000

AddressOfMyNodes=0x20001000,     AddressOfMyNextNode=0x20001004,     MyChainTable[0][0]=0x20001004

AddressOfMyNodes=0x20001004,     AddressOfMyNextNode=0x20001008,     MyChainTable[1][0]=0x20001008

AddressOfMyNodes=0x20001008,     AddressOfMyNextNode=0x2000100c,     MyChainTable[2][0]=0x2000100c

AddressOfMyNodes=0x2000100c,     AddressOfMyNextNode=0x20001010,     MyChainTable[3][0]=0x20001010

AddressOfMyNodes=0x20001010,     AddressOfMyNextNode=0x0,     MyChainTable[4][0]=0x0

*/

//MEMORY_Task任务

void MEMORY_Task(void *pdata)

{

    u8 err,cnt;

    u8 *ptr1,*ptr2;

    printf("%s",MEMORY_Task_rn_REG);

    printf("%s",MEMORY_Task_Initialise_REG);

    while(1)

    {

        cnt++;

        if(cnt>100)

        {

          ptr1 = OSMemGet(INTERNAL_MEM_Pointer,&err);

      //相当于C语言中的malloc()

      //假如从未被申请过,ptr1和根节点地址相等

          ptr2 = OSMemGet(INTERNAL_MEM_Pointer,&err);

      //相当于C语言中的malloc()

          if(ptr1!=NULL) *(u32*)ptr1=0x12345678;

          if(ptr2!=NULL) *(u32*)ptr2=0x87654321;

          if(ptr1!=NULL && ptr2!=NULL)

          {

              printf("%s",MEMORY_Task_rn_REG);

              printf("Address_0x%p=0x%x     ",ptr1,*(u32*)ptr1);

                printf("Address_0x%p=0x%x",ptr2,*(u32*)ptr2);

                PrintMyChainTable();

          }

          if(ptr2!=NULL)//后申请的先释放

          {

              OSMemPut(INTERNAL_MEM_Pointer,ptr2);

        //释放一个内存块,首地址为ptr2

        //相当于C语言中的free()

                ptr2=NULL;

          }

          if(ptr1!=NULL)//先申请的后释放

          {

              OSMemPut(INTERNAL_MEM_Pointer,ptr1);

        //释放一个内存块,首地址为ptr1

        //相当于C语言中的free()

                ptr1=NULL;

          }

            PrintMyChainTable();

            printf("%s",MEMORY_Task_rn_REG);

          cnt=0;

      }

        OSTimeDlyHMSM(0,0,0,1000);//延时1000ms

    }

}

你可能感兴趣的:(产品研发,uCOSii,实时操作系统,RTOS,内存管理,单片机)