转载自https://blog.csdn.net/zhoutaopower/article/details/106631237

FreeRTOS 提供了5种内存堆管理方案,分别对应heap1/heap2/heap3/heap4/heap5,提供内存管理是作为 OS 的一项基本功能,FreeRTOS 根据具体的使用场景,将内存管理按需切分成为了 5 部分,以供不同的场景来针对性使用;

其实库函数的 malloc 和 free 已经是提供了内存的动态管理功能,但是呢介于一下几个原因:

  • 在嵌入式系统中,它们并不总是可以使用的;
  • 它们会占用更多宝贵的代码空间;
  • 它们没有线程保护;
  • 它们不具有确定性(每次调用执行的时间可能会不同);

在小型实时嵌入式 OS 中,使用 malloc 和 free,并不是最明智的选择;所以,FreeRTOS 使用了:pvPortMallo() 和 vPortFree() 函数来代替 malloc() 和 free() 函数,来进行内存管理;

FreeRTOS 内存管理相关的 SourceCode 放置在:

FreeRTOS\Source\portable\MemMang

一共 5 个,今天就来看看第一种内存管理 heap1 是如何实现的;

1、内存大小

heap1 中有几个关键的宏定义:

configTOTAL_HEAP_SIZE

这个是需要用户根据自己的芯片具体情况来定义的,FreeRTOS 管理的内存就来自于这个值:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];

ucHeap 就是管理的对象;

 

2、对齐

有的处理器是对内存对齐有要求的,比如 ARM-CM3 等,AAPCS规则要求堆栈保持8字节对齐。给任务分配栈时需要保证栈是8字节对齐的。所以这里 FreeRTOS 就需要涉及到对齐操作;针对 ARM-CM3 这类处理器来说,在portmacro.h 文件中,定义了对齐的字节数:


/* Hardware specifics. */ #define portBYTE_ALIGNMENT 8

而在 portable.h 中,定义了对应的 Mask(8字节对齐,那么都要是 8 的倍数,也就是二进制的 4'b1000,所以 MASK 是 4'b0111 也就是 0x07):


#if portBYTE_ALIGNMENT == 8
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
#endif

 

3、分配内存

分配内存使用了 pvPortMalloc 函数,入参是希望分配的 Size,返回值是分配到内存的起始地址,失败的话返回 NULL:

/* Index into the ucHeap array. */
static size_t xNextFreeByte = ( size_t ) 0; void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn = NULL;
static uint8_t *pucAlignedHeap = NULL; /* Ensure that blocks are always aligned to the required number of bytes. */
#if( portBYTE_ALIGNMENT != 1 )
{
if( xWantedSize & portBYTE_ALIGNMENT_MASK )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
}
}
#endif vTaskSuspendAll();
{
if( pucAlignedHeap == NULL )
{
/* Ensure the heap starts on a correctly aligned boundary. */
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
} /* Check there is enough room left for the allocation. */
if( ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) &&
( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) )/* Check for overflow. */
{
/* Return the next free byte then increment the index past this
block. */
pvReturn = pucAlignedHeap + xNextFreeByte;
xNextFreeByte += xWantedSize;
} traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll(); #if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
}
#endif return pvReturn;
}

pvReturn 就是如果被分配到内存后的起始地址,初始化成为 NULL;

这里注意一下,pucAlignedHeap 是一个 static 变量,它记录了对齐后,内存 heap 的起始地址;

如果 portBYTE_ALIGNMENT != 1,也就是使用了对齐,那么需要按需来调整分配内存的大小,也就是 xWantedSize,使其能够达到对齐的效果;

接着调用 vTaskSuspendAll();,暂时关闭 OS 调度;

接着对初始的 ucHeap[ configTOTAL_HEAP_SIZE ] 进行对齐操作:

/* Ensure the heap starts on a correctly aligned boundary. */
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );

这里为什么是 ucHeap[ portBYTE_ALIGNMENT ] 呢,因为如果 ucHeap 的起始地址本就不对齐的话,那么经过对齐操作后得到的地址,便可能小于真实的 ucHeap,所以这里往前挪了一点;

接下来便是检查是否能够正常分配到想要的 Size 的内存,xNextFreeByte 记录了不断的分配内存后,可用于分配内存在 ucHeap 的起始地址;这里的 configADJUSTED_HEAP_SIZE 很关键,它被定义为:

/* A few bytes might be lost to byte aligning the heap start address. */

#define configADJUSTED_HEAP_SIZE    ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )

也就是在 configTOTAL_HEAP_SIZE 基础之上预留出了 portBYTE_ALIGNMENT 的空间,这个就是用于了刚刚上一步说的 ucHeap[ portBYTE_ALIGNMENT ] 这部分空间;

如果分配成功,那么 pvReturn 被更新为 ucHeap 对齐后的起始地址,加上可用内存的起始地址指针 xNextFreeByte;

同时,更新 xNextFreeByte 指针;

整个过程,保证了 ucHeap 的起始地址对齐到 pucAlignedHeap,分配内存的时候,Size 是对齐的;

然后再调用 xTaskResumeAll(); 来恢复 OS 调度;

当然,如果定义了 configUSE_MALLOC_FAILED_HOOK,在分配失败的时候,会去调用 vApplicationMallocFailedHook 回调;

 

4、小结

heap1 不提供 Free 内存的接口,也就是说,这套内存管理是只提供的分配,一旦申请成功后,这块内存再也不能被释放;实际上,大多数的嵌入式系统并不需要动态删除任务、信号量、队列等,而是在初始化的时候一次性创建好,便一直使用,永远不用删除。所以这个内存管理策略实现简洁、安全可靠,使用的非常广泛。

FreeRTOS --(2)内存管理 heap1的更多相关文章

  1. 轻量级操作系统FreeRTOS的内存管理机制(一)

    本文由嵌入式企鹅圈原创团队成员朱衡德(Hunter_Zhu)供稿. 近几年来,FreeRTOS在嵌入式操作系统排行榜中一直位居前列,作为开源的嵌入式操作系统之一,它支持许多不同架构的处理器以及多种编译 ...

  2. FreeRTOS 动态内存管理

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 动态内存管理,动态内存管理是 FreeRTOS 非常重要的一项功能,前面 ...

  3. FreeRTOS的内存管理

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

  4. freertos之内存管理

    任务.信号量.邮箱才调度器开始调度之前就应该创建,所以它不可能像裸奔程序那样的函数调用能确定需要多少内存资源,RTOS提供了3种内存管理的方法: 1 方法一:确定性好适合于任务.信号量.队列都不被删除 ...

  5. FreeRTOS --(3)内存管理 heap2

    在<FreeRTOS --(2)内存管理 heap1>知道 heap 1 的内存管理其实只是简单的实现了内存对齐的分配策略,heap 2 的实现策略相比 heap 1 稍微复杂一点,不仅仅 ...

  6. FreeRTOS内存管理

    简介 Freertos的内存管理分别在heap_1.c,heap_2.c,heap_3.c,heap_4.c,heap_5.c个文件中,选择合适的一种应用于嵌入式项目中即可. 本文的图片中 红色部分B ...

  7. FreeRTOS --(6)内存管理 heap5

    转载自https://blog.csdn.net/zhoutaopower/article/details/106748308 FreeRTOS 中的 heap 5 内存管理,相对于 heap 4&l ...

  8. FreeRTOS --(5)内存管理 heap4

    FreeRTOS 中的 heap 4 内存管理,可以算是 heap 2 的增强版本,在 <FreeRTOS --(3)内存管理 heap2>中,我们可以看到,每次内存分配后都会产生一个内存 ...

  9. FreeRTOS--堆内存管理

    因为项目需要,最近开始学习FreeRTOS,一开始有些紧张,因为两个星期之前对于FreeRTOS的熟悉度几乎为零,经过对FreeRTOS官网的例子程序的摸索,和项目中问题的解决,遇到了很多熟悉的身影, ...

随机推荐

  1. 使用 Spring Cloud 有什么优势?

    使用 Spring Boot 开发分布式微服务时,我们面临以下问题 与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题. 服务发现-服务发现工具管理群集中的流程和服务如何查找 ...

  2. Spring Boot 2.X 有什么新特性?与 1.X 有什么区别?

    配置变更JDK 版本升级第三方类库升级响应式 Spring 编程支持HTTP/2 支持配置属性绑定更多改进与加强-

  3. maven常用命令含义

    今天在开发过程中,对一个mapper.xml文件的sql进行了改动,重启tomcat后发现没有生效,首先考虑是不是远程服务开启着,导致代码没有走本地,确认远程服务是关闭的,的确是本地修改没有生效,于是 ...

  4. java-設計模式-抽象工場模式

    抽象工廠模式AbstractFactory 一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类. 工廠方法模式中考虑的是一类产品的生产,如畜牧场只养动物.电视机厂只生产电视机,同种类 ...

  5. TCP(三)

    1.三次握手 置位概念:根据TCP的包头字段,存在3个重要的标识ACK.SYN.FIN ACK:表示验证字段 SYN:位数置1,表示建立TCP连接 FIN:位数置1,表示断开TCP连接 三次握手过程说 ...

  6. MM32F0020 UART1硬件自动波特率的使用

    目录: 1.MM32F0020简介 2.UART自动波特率校准应用场景 3.MM32F0020 UART自动波特率校准原理简介 4.MM32F0020 UART1 NVIC硬件自动波特率配置以及初始化 ...

  7. Java/C++实现模板方法模式---数据库操作

    对数据库的操作一般包括连接.打开.使用.关闭等步骤,在数据库操作模板类中我们定义了connDB().openDB().useDB().closeDB()四个方法分别对应这四个步骤.对于不同类型的数据库 ...

  8. APK安装流程概述

    pre { background: none left top repeat scroll rgba(0, 0, 0, 0); border: 1px solid rgba(0, 0, 0, 1); ...

  9. SpringMVC异常(404,接收参数类型转换错误)

    内容 一.异常信息 HTTP Status 400 - type Status report message description The request sent by the client wa ...

  10. vue项目中返回之前页面数据不刷新的问题

    利用vue做项目的时候会有让用户选择当前页面的某些数据,然后再跳到下一页,而下一页是根据上一页的数据来的,有时候选择了上一页的不同选项,下一页的数据可能还是之前的 这个就属于vue的数据获取问题 解决 ...