一、在Ucos-III中使用的内存管理方式在os_mem.c中
二、实现方式
(1):创建函数
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) //错误的返回值
参数标记上图了,基本的意思就是你创建一大块连续的内存然后交给ucos去控制这一块内存,由他来去分配,你可以用函数去调取或者释放
原理:
相当于你创建的一大块内存空间被ucos去控制,首先实现的就是对你参数的检查,查看你传递进来的参数是否是合理的参数
if (p_addr == (void *)0) { /* Must pass a valid address for the memory part. */
*p_err = OS_ERR_MEM_INVALID_P_ADDR;
return;
}
if (n_blks < (OS_MEM_QTY)2) { /* Must have at least 2 blocks per partition */
*p_err = OS_ERR_MEM_INVALID_BLKS;
return;
}
if (blk_size < sizeof(void *)) { /* Must contain space for at least a pointer */
*p_err = OS_ERR_MEM_INVALID_SIZE;
return;
}
align_msk = sizeof(void *) - 1u;
if (align_msk > 0) {
if (((CPU_ADDR)p_addr & align_msk) != 0u){ /* Must be pointer size aligned */
*p_err = OS_ERR_MEM_INVALID_P_ADDR;
return;
}
if ((blk_size & align_msk) != 0u) { /* Block size must be a multiple address size */
*p_err = OS_ERR_MEM_INVALID_SIZE;
}
}
这些功能基本伤就是去检验你的传参是否正确,简单理解就是这样,然后关键的来了,真正管理内存的部分
p_link = (void **)p_addr; /* Create linked list of free memory blocks */
p_blk = p_addr;
loops = n_blks - 1u;
for (i = 0u; i < loops; i++) {
p_blk += blk_size;
*p_link = (void *)p_blk; /* Save pointer to NEXT block in CURRENT block */
p_link = (void **)(void *)p_blk; /* Position to NEXT block */
}
*p_link = (void *)0; /* Last memory block points to NULL */
OS_CRITICAL_ENTER();
p_mem->Type = OS_OBJ_TYPE_MEM; /* Set the type of object */
p_mem->NamePtr = p_name; /* Save name of memory partition */
p_mem->AddrPtr = p_addr; /* Store start address of memory partition */
p_mem->FreeListPtr = p_addr; /* Initialize pointer to pool of free blocks */
p_mem->NbrFree = n_blks; /* Store number of free blocks in MCB */
p_mem->NbrMax = n_blks;
p_mem->BlkSize = blk_size; /* Store block size of each memory blocks */
这里运用的思想基本就是链表的思维,将内存块去拆分成小的单元,然后运用链表的前一个节点去存储后一个节点的地址,这样将链表连起来,值得一提的是这个2次指针,因为需要存储地址且不本身自己也为地址,所以将后一个节点的地址存入前一个节点的时候需要将前一个节点转为2次指针在解一次引用即可存储。最后将末尾的节点设置为NULL
下面就是结构体赋值,存储管理的内存信息(多少个、多大、名字、可用的还有多少、这些)
(2):调取函数
void *OSMemGet (OS_MEM *p_mem, //就是你要调取那一块内存
OS_ERR *p_err) //错误值
这个函数很简单,基本就是你创建完了,然后你去调取一个他就给你返回一个指向该控制块的指针。
(3):释放函数
void OSMemPut (OS_MEM *p_mem, //释放给哪里
void *p_blk, //释放的地址
OS_ERR *p_err) //错误值
这个也简单,就是你如果你申请的内存你不想用了,就调用这个把他归还给ucos去控制释放。
原理:
这俩的原理基本一致,都是看是需要取出内存块还是归还内存块,取出就返回控制块的指针,然后再将剩下的用链表连接起来,归还的话就是相当于链表的插入。