完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
一个处理器,在不断地分配和释放内存的过程中,一整块连续的内存被分散为很多离散的小块内存,这些叫做内存碎片,内存碎片过多会导致内存的浪费。uC/OS 的内存管理机制就是为了尽量减少内存碎片。大致的思路是一次性取出一个较大的内存分区,把这个内存分区分成若干个内存块,然后将内存块逐个串成单向链表。每次要用到内存块就从内存分区中取出一块,用完就放回去。这跟消息队列的消息池的使用原理是一样的。
如果想要使用内存管理机制,就必须事先使能内存管理。内存管理的使能位于“os_cfg.h”。 /* -------------------------- MEMORY MANAGEMENT ------------------------ */ #define OS_CFG_MEM_EN 1u //使能/禁用内存管理 |
|
|
|
OSMemCreate ()
要使用 uC/OS 的内存管理必须先声明和创建内存管理对象,调用 OSMemCreate () 函数可以创建一个内存管理对象。注意,内存分区一经创建便不能删除,系统没有提供相应的删除函数。OSMemCreate () 函数的信息如下表所示。 |
|
|
|
OSMemCreate () 函数的定义位于“os_mem.c:
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) //返回错误类型 { #if OS_CFG_ARG_CHK_EN 》 0u CPU_DATA align_msk; #endif OS_MEM_QTY i; OS_MEM_QTY loops; CPU_INT08U *p_blk; void **p_link; //二级指针,存放指针的指针 CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和 //定义一个局部变量,用于保存关中断前的 CPU 状态寄存器 // SR(临界段关中断只需保存SR),开中断时将该值还原。 #ifdef OS_SAFETY_CRITICAL //如果使能了安全检测 if (p_err == (OS_ERR *)0) { //如果错误类型实参为空 OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数 return; //返回,停止执行 } #endif #ifdef OS_SAFETY_CRITICAL_IEC61508 //如果使能了安全关键 if (OSSafetyCriticalStartFlag == DEF_TRUE) { //如果在调用OSSafetyCriticalStart()后创建 *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; //错误类型为“非法创建内核对象” return; //返回,停止执行 } #endif #if OS_CFG_CALLED_FROM_ISR_CHK_EN 》 0u //如果使能了中断中非法调用检测 if (OSIntNestingCtr 》 (OS_NESTING_CTR)0) { //如果该函数是在中断中被调用 *p_err = OS_ERR_MEM_CREATE_ISR; //错误类型为“在中断中创建对象” return; //返回,停止执行 } #endif #if OS_CFG_ARG_CHK_EN 》 0u //如果使能了参数检测 if (p_addr == (void *)0) { //如果 p_addr 为空 *p_err = OS_ERR_MEM_INVALID_P_ADDR; //错误类型为“分区地址非法” return; //返回,停止执行 } if (n_blks 《 (OS_MEM_QTY)2) { //如果分区的内存块数目少于2 *p_err = OS_ERR_MEM_INVALID_BLKS; //错误类型为“内存块数目非法” return; //返回,停止执行 } if (blk_size 《 sizeof(void *)) { //如果内存块空间小于指针的 *p_err = OS_ERR_MEM_INVALID_SIZE; //错误类型为“内存空间非法” return; //返回,停止执行 } align_msk = sizeof(void *) - 1u; //开始检查内存地址是否对齐 if (align_msk 》 0u) { if (((CPU_ADDR)p_addr & align_msk) != 0u){ //如果分区首地址没对齐 *p_err = OS_ERR_MEM_INVALID_P_ADDR; //错误类型为“分区地址非法” return; //返回,停止执行 } if ((blk_size & align_msk) != 0u) { //如果内存块地址没对齐 *p_err = OS_ERR_MEM_INVALID_SIZE; //错误类型为“内存块大小非法” return; //返回,停止执行 } } #endif /* 将空闲内存块串联成一个单向链表 */ p_link = (void **)p_addr; //内存分区首地址转为二级指针 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; //在当前内存块保存下一个内存块地址 p_link = (void **)(void *)p_blk; //下一个内存块的地址转为二级指针 } *p_link = (void *)0; //最后一个内存块指向空 OS_CRITICAL_ENTER(); //进入临界段 p_mem-》Type = OS_OBJ_TYPE_MEM; //设置对象的类型 p_mem-》NamePtr = p_name; //保存内存分区的命名 p_mem-》AddrPtr = p_addr; //存储内存分区的首地址 p_mem-》FreeListPtr = p_addr; //初始化空闲内存块池的首地址 p_mem-》NbrFree = n_blks; //存储空闲内存块的数目 p_mem-》NbrMax = n_blks; //存储内存块的总数目 p_mem-》BlkSize = blk_size; //存储内存块的空间大小 #if OS_CFG_DBG_EN 》 0u //如果使能了调试代码和变量 OS_MemDbgListAdd(p_mem); //将内存管理对象插入内存管理双向调试列表 #endif OSMemQty++; //内存管理对象数目加1 OS_CRITICAL_EXIT_NO_SCHED(); //退出临界段(无调度) *p_err = OS_ERR_NONE; //错误类型为“无错误” } OSMemCreate() 如果使能了 OS_CFG_DBG_EN(位于“os_cfg.h”),创建内存管理对象时还会调用OS_MemDbgListAdd () 函数将该内存管理对象插入到一个内存管理调试列表,是为方便调试所设。 |
|
|
|
OS_MemDbgListAdd () 函数的定义位于“os_mem.c”:
#if OS_CFG_DBG_EN 》 0u //如果使能了调试代码和变量 void OS_MemDbgListAdd (OS_MEM *p_mem) //将内存管理对象插入到内存管理调试列表的最前端 { p_mem-》DbgPrevPtr = (OS_MEM *)0; //将该对象作为列表的最前端 if (OSMemDbgListPtr == (OS_MEM *)0) { //如果列表为空 p_mem-》DbgNextPtr = (OS_MEM *)0; //该队列的下一个元素也为空 } else { //如果列表非空 p_mem-》DbgNextPtr = OSMemDbgListPtr; //列表原来的首元素作为该队列的下一个元素 OSMemDbgListPtr-》DbgPrevPtr = p_mem; //原来的首元素的前面变为了该队列 } OSMemDbgListPtr = p_mem; //该对象成为列表的新首元素 } #endif OS_MemDbgListAdd() |
|
|
|
|
|
|
|
OSMemGet () 函数的定义也位于“os_mem.c
void *OSMemGet (OS_MEM *p_mem, //内存管理对象 OS_ERR *p_err) //返回错误类型 { void *p_blk; CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和 //定义一个局部变量,用于保存关中断前的 CPU 状态寄存器 // SR(临界段关中断只需保存SR),开中断时将该值还原。 #ifdef OS_SAFETY_CRITICAL //如果使能了安全检测 if (p_err == (OS_ERR *)0) { //如果错误类型实参为空 OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数 return ((void *)0); //返回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); //返回0(有错误),停止执行 } #endif CPU_CRITICAL_ENTER(); //关中断 if (p_mem-》NbrFree == (OS_MEM_QTY)0) { //如果没有空闲的内存块 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_MEM_NO_FREE_BLKS; //错误类型为“没有空闲内存块” return ((void *)0); //返回0(有错误),停止执行 } p_blk = p_mem-》FreeListPtr; //如果还有空闲内存块,就获取它 p_mem-》FreeListPtr = *(void **)p_blk; //调整空闲内存块指针 p_mem-》NbrFree--; //空闲内存块数目减1 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_NONE; //错误类型为“无错误” return (p_blk); //返回获取到的内存块 } OSMemGet |
|
|
|
|
|
|
|
OSMemPut () 函数的定义也位于“os_mem.c”:
void OSMemPut (OS_MEM *p_mem, //内存管理对象 void *p_blk, //要退回的内存块 OS_ERR *p_err) //返回错误类型 { CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和 //定义一个局部变量,用于保存关中断前的 CPU 状态寄存器 // SR(临界段关中断只需保存SR),开中断时将该值还原。 #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_mem 为空 *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++; //空闲内存块数目加1 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_NONE; //错误类型为“无错误” } |
|
|
|
只有小组成员才能发言,加入小组>>
960 浏览 1 评论
1106 浏览 1 评论
12524 浏览 0 评论
5938 浏览 3 评论
17729 浏览 6 评论
1030浏览 1评论
1030浏览 1评论
961浏览 1评论
4898浏览 1评论
1107浏览 1评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-27 17:59 , Processed in 1.186280 second(s), Total 92, Slave 74 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号