内存管理
uC/OS-III可以获得连续的内存块。内存块大小可以相同, 所有的内存分
区包含了整数个内存块。 在特定的时间执行内存块的分配和释放。内存分
区以内存块数组的形式被静态分配的。如果分配后不被释放,也可以调用
malloc()动态分配。
不要在嵌入式系统中使用malloc()和free(),因为这样会导致内存碎片。
可以同时有多个内存分区且每个分区的内存块个数和大小可以不同,
根据需求设置, 但内存块被分配后必须返回给它所在的内存分区。
这种管理方式仅会导致内存块块内的碎片, 决定于应用中所设置内存块的大小。
1.创建一个内存分区
在使用内存分区之前必须创建它。这样uC/OS-III就可以知道这个内
存分区的相关信息并管理他们。调用OSMemCreate()创建一个内存分区。
( 1) 当创建一个内存分区时, 内存控制块(OS_MEM)的地址需作为参数被提供。 通常内存控制块从静态内存中分配,
然而, 也可以调用malloc()从堆中获得。用户代码不能释放内存控制块。
( 2) OSMemCreate()将内存块链接起来并将其链表的首地址赋值给OS_MEM结构体。
( 3)每个内存块的大小必须大于一个指针。
2.获得内存分区中的内存块
应用代码通过调用OSMemGet()可以从内存分区中申请内存块。
3. 归还内存块给内存分区
当用户对内存块的使用完毕后,必须将该内存块归还给对应的内
存分区。调用OSMemPut()实现这个功能。
4 .使用内存分区
编译时设置OS_CFG.H中的OS_CFG_MEM_EN为1开启内存管理服务。
函数名 | 功能 |
OSMemCreate() | 创建一个内存分区 |
OSMemGet() | 从内存分区中获得一个内存块 |
OSMemPut() | 归还一个内存块给相应的内存分区 |
OSMemCreate()只能在任务级被调用,但是OSMemGet()和OSMemPut()可以在ISR中被调用。
5.列表显示了如何动态地分配内存。 在这个例子中, 左边任务读取模拟输入值(可以是压力、温度、电压),
并发送消息给右边任 务,消息中包含了根据模拟输入所计算出的相关信息的地址。在这个例子中错误的处理被集
中在右边任务中。其它任务或ISR也可以发送消息给该错误处理任务。
( 1) 任务读取模拟输入。 如果测得模拟输入超范围, 就发送消息给错误处理函数。
( 2)任务从内存分区中申请一个内存块用于存放检测模拟输入所得的相关数据。
( 3)任务将检测模拟输入所得的相关数据存入内存块。然而,没必要在内存块中存放时间戳因为时间戳被存放在消息中。
( 4) 任务提交消息给错误处理任务。 当然, 错误处理任务知道消息中所包含的数据的含义。 一旦消息被发送, 发送者任务不能再访
问消息所指向的内存块。
( 5)错误处理任务通常在消息队列中等待。
( 6)错误处理任务接收到消息后,执行相应的操作。
( 7) 错误处理任务处理完毕相应的操作后, 将内存块归还给对应的内存分区。 因此, 发送者和接收者都必须知道内存块是属于哪个
内存分区的,或者发送者可以将内存分区的地址作为要发送消息的数据中的一部分。 这样, 错误处理函数就知道将这个内存块归还给哪个
内存分区了。
6.任务在内存分区被分配完时可以等待内存块。 uC/OS-III不支持任务等待内存分区,但是可以通过一个信号量
用于内存分区中内存块的分配。
(1)获得一个内存块时, 先调用OSSemPend()获得一个信号量,然后再调用OSMemGet()获得一个内存块。
( 2)释放一个内存块时, 先调用OSMemPut()释放这个内存块,然后再调用OSSemPost()释放这个信号量。
上面的操作必须以这个顺序执行。
用户可以在ISR中使用OSMemGet()和OSMemPut(), 因为这两个函数不会被阻塞且能快速地被执行。
(不能在ISR中调用会引起阻塞的函数)。
结语:
不要在嵌入式系统中使用malloc()和free(),因为这样会导致内存碎片。
可以用malloc()动态的分配内存空间,但不要释放这些内存空间。{就是说定义不需要释放的空间时可以
使用malloc(),这样能使所定义的空间的利用率接近为100%} 。
用户可以创建任意个内存分区(限制于处理器的RAM)。
uC/OS-III中与内存分区相关的函数都是以OSMem???()为前缀。
通过设置OS_CFG.H中的OS_CFG_MEM_EN为1开启内存管理服务。