实验四 uC/OS-II 的内存管理
一、实验目的
掌握嵌入式实时操作系统 uC/OS-II 内存管理中内存分配和回收的功能。
二、实验原理
注意:根据程序中设定的时间延迟,图中的每个栅格对应100个系统时钟周期。为了防止内存申请和释放的不合理导致的大块连续内存被分割成可用性小的小片的问题,uC/OS-II 将用于动态内存分配的空间分成一些固定大小的内存块,根据应用申请的内存大小,分配适当数量的内存块。图的纵坐标就代表内存块。
在 main()函数中,使用 uC/OS-II 的 OSMemCreate()函数创建一个用于动态内存分配的区域。通过传递适当的调用参数,我们在该区域中划分了 2 个 128B 的内存块。如果成功创建这些内存块,uC/OS-II 会在内部建立并维护一个单向链表。
static void MemoryCreate()
//为 OSMemCreate 函数设置包含错误码的变量的指针。
INT8U err;
//OSMemCreate()函数建立并初始化一块内存区。2块,每块128B。
CommMem = OSMemCreate(&CommBuf[0][0], 2, 128, &err);
应用任务使用函数 OSMemGet(CommMem,&err)来申请内存块,根据当前内存区域的情况来判断分配的结果。
应该注意,uC/OS-II 的内存块归还函数是:OSMemPut(CommMem,CommMsg3);
它的返回值只有两种:OS_NO_ERR :成功归还内存块 OS_MEM_FULL :内存区已满,不能再接受更多释放的内存块。出现这种情况说明用户程序出现了错误,归还了多于用 OSMemGet() 函数得到的内存块。
在这个应用中使用了两个函数:
MemInfo(pdata); //函数得到内存区的信息
DispShow(); //将内存区信息显示到屏幕上
三、函数说明
OSMemCreate()函数建立并初始化一块内存区。一块内存区包含指定数目的大小确定的内存块。程序可以包含这些内存块并在用完后释放回内存区。
函数原型:OS_MEM *OSMemCreate( void *addr, INT32U nblks ,INT32U blksize, INT8U *err)。
返回值:OSMemCreate ()函数返回指向内存区控制块的指针。如果没有剩余内存区,OSMemCreate()函数返回空指针。
OSMemGet()函数用于从内存区分配一个内存块。用户程序必须知道所建立的内存块的大小,同时用户程序必须在使用完内存块后释放内存块。可以多次调用 OSMemGet()函数。函数原型:void *OSMemGet(OS_MEM *pmem, INT8U *err)。返回值OSMemGet()函数返回指向内存区块的指针。如果没有空间分配给内存块,OSMemGet()函数返回空指针。
OSMemPut()函数释放一个内存块,内存块必须释放回原先申请的内存区。
函数原型:INT8U OSMemPut( OS_MEM *pmem, void *pblk)。返回值:
OSMemPut()函数的返回值为下述之一:OS_NO_ER成功释放内存块。OS_MEM_FULL :内存区已经不能再接受更多释放的内存块。这种情况说明用户程序出现了错误,释放了多于用 OSMemGet()函数得到的内存块。
OSMemQuery()函数得到内存区的信息。该函数返回 OS_MEM 结构包含的信息,但使用了一个新的 OS_MEM_DATA 的数据结构。OS_MEM_DATA 数据结构还包含了正被使用的内存块数目的域。函数原型:INT8U OSMemQuery(OS_MEM *pmem, OS_MEM_DATA *pdata)。返回值:OSMemQuery()函数返回值总是 OS_NO_ERR。
四、实验内容
本次实验体现出了内核的内存分配策略。源程序的运行结果如下:
初始化的内存区域:
内存块 1 被分配出去;
内存块 2 被分配出去;
之后应用试图申请内存块 3,但此时系统因为没有足够的内存块可以分配,所以失败:
在这里我们为了加深对内存管理的理解,我们在原来基础上增加一个请求:
输出效果如下,可以发现此时内存块的地址已发生变化;
五、实验总结
在本次实验中,我们要意识到指针的重要性。并且在进行实验中,要尽量做到对“指针”的变化心中有数。另外,我们要时刻牢记函数参数在程序中所起到的重要作用以及一些函数的用法和使用条件。除此之外,在任务归还内存块时,不同的归还方式,不会导致内存块地址的变化,但是会导致链表的结构发生变化。但是如果在原有基础上,再增加一个内存块申请的话,这是内存块的地址就会发生变化。由此次实验,我们了解了内存管理的方式。