简介
RTX的链式内存管理非常简单,采用简单链式,因此不建议频繁的分配和释放内存,不然回导致无法避免的内存碎片,以至于系统崩溃。
关键结构
RTX的内存仅仅需要了解一个结构体,如下:
/* Types */
typedef struct mem { /* << Memory Pool management struct >> */
struct mem *next; /* Next Memory Block in the list */
U32 len; /* Length of data block */
} MEMP;
简单的链式结构,把堆划分给应用。
关键代码
主要是三个函数:
-
初始化
-
申请内存
-
释放内存
rt_init_mem
// Initialize Dynamic Memory pool
// Parameters:
// pool: Pointer to memory pool
// size: Size of memory pool in bytes
// Return: 0 - OK, 1 - Error
int rt_init_mem (void *pool, U32 size) {
MEMP *ptr;
if ((pool == NULL) || (size < sizeof(MEMP))) return (1);
ptr = (MEMP *)pool;
ptr->next = (MEMP *)((U32)pool + size - sizeof(MEMP *));
ptr->next->next = NULL;
ptr->len = 0;
return (0);
}
*rt_alloc_mem
// Allocate Memory from Memory pool
// Parameters:
// pool: Pointer to memory pool
// size: Size of memory in bytes to allocate
// Return: Pointer to allocated memory
void *rt_alloc_mem (void *pool, U32 size) {
MEMP *p, *p_search, *p_new;
U32 hole_size;
if ((pool == NULL) || (size == 0)) return NULL;
/* Add header offset to 'size' */
size += sizeof(MEMP);
/* Make sure that block is 4-byte aligned */
size = (size + 3) & ~3;
p_search = (MEMP *)pool;
while (1) {
hole_size = (U32)p_search->next - (U32)p_search;
hole_size -= p_search->len;
/* Check if hole size is big enough */
if (hole_size >= size) break;
p_search = p_search->next;
if (p_search->next == NULL) {
/* Failed, we are at the end of the list */
return NULL;
}
}
if (p_search->len == 0) {
/* No block is allocated, set the Length of the first element */
p_search->len = size;
p = (MEMP *)(((U32)p_search) + sizeof(MEMP));
} else {
/* Insert new list element into the memory list */
p_new = (MEMP *)((U32)p_search + p_search->len);
p_new->next = p_search->next;
p_new->len = size;
p_search->next = p_new;
p = (MEMP *)(((U32)p_new) + sizeof(MEMP));
}
return (p);
}
rt_free_mem
// Free Memory and return it to Memory pool
// Parameters:
// pool: Pointer to memory pool
// mem: Pointer to memory to free
// Return: 0 - OK, 1 - Error
int rt_free_mem (void *pool, void *mem) {
MEMP *p_search, *p_prev, *p_return;
if ((pool == NULL) || (mem == NULL)) return (1);
p_return = (MEMP *)((U32)mem - sizeof(MEMP));
/* Set list header */
p_prev = NULL;
p_search = (MEMP *)pool;
while (p_search != p_return) {
p_prev = p_search;
p_search = p_search->next;
if (p_search == NULL) {
/* Valid Memory block not found */
return (1);
}
}
if (p_prev == NULL) {
/* First block to be released, only set length to 0 */
p_search->len = 0;
} else {
/* Discard block from chain list */
p_prev->next = p_search->next;
}
return (0);
}
关键实现
先来看看大概的内存管理图:
MEMP | ... | MEMP | ... | MEMP | ||||
next | len | ... | next | len | ... | ... | ... | next |
其中省略号表示拥护申请使用的堆。末尾仅仅使用了next指针。
在初始化时,给定一个地址和大小,传给__int rt_init_mem (void *pool, U32 size)__处理完后,就变成如下图所示:
MEMP | ... | MEMP | |||
mem_base | 0 | ... | ... | ... | NULL |
然后在N次调用__void *rt_alloc_mem (void *pool, U32 size)__后,这条链式存储就会被切成N段。
调用__int rt_free_mem (void *pool, void *mem)__释放内存,相邻堆就会合并。
从这就可以看出,为什么不适合频繁的申请和释放堆了,由于用于RTOS,面临小资源的使用,为了减小开销,不支持碎片整理使用链式存储也是一种适应。