(原创)RTOS-RTX分析系列之链式内存

2017/07/19 RTX

简介

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;

简单的链式结构,把堆划分给应用。

关键代码

主要是三个函数:

  1. 初始化

  2. 申请内存

  3. 释放内存

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,面临小资源的使用,为了减小开销,不支持碎片整理使用链式存储也是一种适应。


知识共享许可协议
本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

站内搜索

    撩我备注-博客

    joinee

    目录结构