亲宝软件园·资讯

展开

FreeRTOS内存管理

zhzht19861011 人气:0

前言

本文介绍内存管理的基础知识,详细源码分析见《 FreeRTOS内存管理示例分析

FreeRTOS提供了几个内存堆管理方案,有复杂的也有简单的。其中最简单的管理策略也能满足很多应用的要求,比如对安全要求高的应用,这些应用根本不允许动态内存分配的。

FreeRTOS也允许你自己实现内存堆管理,甚至允许你同时使用两种内存堆管理方案。同时实现两种内存堆允许任务堆栈和其它RTOS对象放置到快速的内部RAM,应用数据放置到低速的外部RAM。

每当创建任务、队列、互斥量、软件定时器、信号量或事件组时,RTOS内核会为它们分配RAM。标准函数库中的malloc()和free()函数有些时候能够用于完成这个任务,但是:

      因此,提供一个替代的内存分配方案通常是必要的。

      嵌入式/实时系统具有千差万别的RAM和时间要求,因此一个RAM内存分配算法可能仅属于一个应用的子集。

      为了避免这个问题,FreeRTOS在移植层保留内存分配API函数。移植层在RTOS核心代码源文件之外(不属于核心源代码),这使得不同的应用程序可以提供适合自己的应用实现。当RTOS内核需要RAM时,调用pvPortMallo()函数来代替malloc()函数。当RAM要被释放时,调用vPortFree()函数来代替free()函数。

      FreeRTOS下载包中提供5种简单的内存分配实现,本文稍后会进行描述。用户可以适当的选择其中的一个,也可以自己设计内存分配策略。

      FreeRTOS提供的内存分配方案分别位于不同的源文件(heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c)之中,源文件位于下载包\FreeRTOS\Source\portable\MemMang文件夹中。其它实现方法可以根据需要增加。如果要使用FreeRTOS提供的内存堆分配方案,选中的源文件必须被正确的包含到工程文件中。

1.heap_1.c

这是所有实现中最简单的一个。一旦分配内存之后,它甚至不允许释放分配的内存。尽管这样,heap_1.c还是适用于大部分嵌入式应用程序。这是因为大多数深度嵌入式(deeplyembedded)应用只是在系统启动时创建所有任务、队列、信号量等,并且直到程序结束都会一直使用它们,永远不需要删除。

当需要分配RAM时,这个内存分配方案只是简单的将一个大数组细分出一个子集来。大数组的容量大小通过FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏来设置。

API函数xPortGetFreeHeapSize()返回未分配的堆栈空间总大小,可以通过这个函数返回值对configTOTAL_HEAP_SIZE进行合理的设置。

功能简介:

2.heap_2.c

和方案1不同,这个方案使用一个最佳匹配算法,它允许释放之前分配的内存块。它不会把相邻的空闲块合成一个更大的块(换句话说,这会造成内存碎片)。

有效的堆栈空间大小由位于FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏来定义。

 API函数xPortGetFreeHeapSize()返回剩下的未分配堆栈空间的大小(可用于优化设置configTOTAL_HEAP_SIZE宏的值),但是不能提供未分配内存的碎片细节信息。

功能简介:

可以用于重复的分配和删除具有相同堆栈空间的任务、队列、信号量、互斥量等等,并且不考虑内存碎片的应用程序。

不能用在分配和释放随机字节堆栈空间的应用程序

如果你的应用程序中的队列、任务、信号量、互斥量等等处在一个不可预料的顺序,则可能会导致内存碎片问题,虽然这是小概率事件,但必须牢记。

不具有确定性,但是它比标准库中的malloc函数具有高得多的效率。

      heap_2.c适用于需要动态创建任务的大多数小型实时系统(smallreal time)。

3.heap_3.c

heap_3.c简单的包装了标准库中的malloc()和free()函数,包装后的malloc()和free()函数具备线程保护。

功能简介:

注:使用heap_3时,FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE宏定义没有作用。

4.heap_4.c

这个方案使用一个最佳匹配算法,但不像方案2那样。它会将相邻的空闲内存块合并成一个更大的块(包含一个合并算法)。

有效的堆栈空间大小由位于FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE来定义。

API函数xPortGetFreeHeapSize()返回剩下的未分配堆栈空间的大小(可用于优化设置configTOTAL_HEAP_SIZE宏的值),但是不能提供未分配内存的碎片细节信息。

功能简介:

      heap_4.c还特别适用于移植层代码,可以直接使用pvPortMalloc()和 vPortFree()函数来分配和释放内存。

5.heap_5.c(V8.1.0新增)

这个方案同样实现了heap_4.c中的合并算法,并且允许堆栈跨越多个非连续的内存区。

Heap_5通过调用vPortDefineHeapRegions()函数实现初始化,在该函数执行完成前不允许使用内存分配和释放。创建RTOS对象(任务、队列、信号量等等)会隐含的调用pvPortMalloc(),因此必须注意:使用heap_5创建任何对象前,要先执行vPortDefineHeapRegions()函数。

vPortDefineHeapRegions()函数只需要单个参数。该参数是一个HeapRegion_t结构体类型数组。HeapRegion_t在portable.h中定义,如下所示:

  typedef struct HeapRegion  
  {  
      /* 用于内存堆的内存块起始地址*/  
      uint8_t *pucStartAddress;  
    
      /* 内存块大小 */  
      size_t xSizeInBytes;  
  } HeapRegion_t;

这个数组必须使用一个NULL指针和0字节元素作为结束,起始地址必须从小到大排列。下面的代码段提供一个例子。MSVCWin32模拟器演示例程使用了heap_5,因此可以当做一个参考例程。

 /* 在内存中为内存堆分配两个内存块.第一个内存块0x10000字节,起始地址为0x80000000, 
 第二个内存块0xa0000字节,起始地址为0x90000000.起始地址为0x80000000的内存块的 
 起始地址更低,因此放到了数组的第一个位置.*/  
 const HeapRegion_t xHeapRegions[] =  
 {  
     { ( uint8_t * ) 0x80000000UL, 0x10000 },  
     { ( uint8_t * ) 0x90000000UL, 0xa0000 },  
     { NULL, 0 } /* 数组结尾. */  
 };  
 /* 向函数vPortDefineHeapRegions()传递数组参数. */  
 vPortDefineHeapRegions( xHeapRegions ); 

加载全部内容

相关教程
猜你喜欢
用户评论