问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

FreeRTOS入门——内存管理

创作时间:
作者:
@小白创作中心

FreeRTOS入门——内存管理

引用
CSDN
1.
https://m.blog.csdn.net/weixin_54221545/article/details/141925281

FreeRTOS是目前最受欢迎的实时操作系统(RTOS)内核之一,广泛应用于各种嵌入式系统中。内存管理是RTOS的核心功能之一,FreeRTOS提供了多种内存管理方案,以满足不同应用场景的需求。本文将详细介绍FreeRTOS的内存管理机制,帮助读者更好地理解和使用这一强大的功能。

一、堆和栈

堆(heap):就是一块空闲的内存

  • malloc:从堆里划出一块空间给程序使用
  • free:使用完,将这块内存空间标记为“空闲”,可以再次使用

栈(stack):函数调用的局部变量保存在栈中,当前程序的环境也保存在栈中

  • 可以从堆中分配一块内存空间用作栈

二、内存管理方法

FreeRTOS内存管理接口函数为:pvPortMallocvPortFree,对应mallocfree。源码中默认提供5个文件,对应内存管理的五种方法。

1. heap_1

只有pvPortMalloc,没有vPortFree,首先定义一个大数组,在pvPortMalloc时,从这个数组中分配空间。FreeRTOS在创建任务时,需要2个内核对象:task control block(TCB)和stack,使用heap_1时分配过程如下:

  • A:创建任务之前,整个数组为空闲状态
  • B:创建任务1,蓝色区域被划分
  • C:创建3个任务后数组的分配情况

2. heap_2

支持pvPortMallocvPortFree,使用最佳匹配算法(best fit)分配内存,碎片化严重

最佳匹配算法:假设heap有3块空闲内存:5字节、25字节、100字节,pvPortMalloc想申请20字节,会找出最小且能满足pvPortMalloc的内存:25字节,将其划分为20字节和5字节,其余5字节仍然是空闲状态可以使用。分配过程如下:

  • A:创建了3个任务
  • B:删除了一个任务,空闲内存包括顶部空间、被删除的TCB空间和被删除的Stack空间
  • C:创建了一个新任务,与被删除任务空间相同,刚好分配至原内存3

3. heap_3

heap_3使用标准C库中的mallocfree函数,所有堆大小由链接器的配置决定,配置项configTOTAL_HEAP_SIZE不起作用。

C库中的mallocfree函数并非线程安全的,heap_3会先暂停FreeRTOS的调度器,再去调用函数,实现线程安全

4. heap_4

heap_4也是使用大数组来分配内存,通过首次适应算法来分配内存,还会将相邻空闲内存合并为一个更大的空闲内存,有助于减少内存碎片的问题。

首次适应算法(first fit):假设有三块空闲内存:5字节、200字节、100字节,pvPortMalloc想申请20字节,首先找出第一个能满足pvPortMalloc的内存:200字节,将其划分为20字节和180字节,返回20字节的地址,其余180字节仍然为空闲状态。分配过程如下:

  • A:创建了3个任务
  • B:删除了一个任务,空闲Stack和TCB被合并,空闲内存包括顶层和任务两块内存
  • C:分配了一个Queue,从第一个空闲块中分配部分空间
  • D:分配了一个User数据,从Queue后面的空闲块中分配
  • E:释放Queue,User前后都包含一款空闲内存
  • F:释放User数据,中间的空闲内存合并为一个更大的空闲内存

5. heap_5

heap_5与heap_4内存分配、释放的算法一致,相比于heap_4,heap_5并不局限于管理一个大型数组,它可以管理多块、分隔开的内存。

内存地址不连续可以使用heap_5,在使用前需要确定这些内存块在哪、多大:

** 在使用pvPortMalloc 之前,必须先指定内存块的信息 **

** 使用vPortDefineHeapRegions 来指定这些信息**

如何指定一块内存,使用如下结构体:

typedef struct HeapRegion 
{ 
    uint8_t * pucStartAddress; // 起始地址 
    size_t xSizeInBytes;       // 大小 
} HeapRegion_t;   

如何指定多块内存,使用HeapRegion_t数组,在这个数组中,低地址在前、高地址在后:

HeapRegion_t xHeapRegions[] = 
{ 
    { ( uint8_t * ) 0x80000000UL, 0x10000 }, // 起始地址 0x80000000,大小 0x10000 
    { ( uint8_t * ) 0x90000000UL, 0xa0000 }, // 起始地址 0x90000000,大小 0xa0000 
    { NULL, 0 } // 表示数组结束 
};  

xHeapRegions 数组传给vPortDefineHeapRegions 函数,即可初始化Heap_5。vPortDefineHeapRegions 函数原型如下:

void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions );   

三、Heap相关函数

1. pvPortMalloc/vPortFree

作用:分配内存、释放内存

分配不成功返回值为NULL

void * pvPortMalloc( size_t xWantedSize ); 
void vPortFree( void * pv );  

2. xPortGetFreeHeapSize

作用::当前还有多少空闲内存,Heap_3中无法使用

可以用来优化内存的使用情况,当所有内核对象都分配好,执行此函数发现返回2000,说明还有2000空闲内存,那么configTOTAL_HEAP_SIZE 就可减小2000。

size_t xPortGetFreeHeapSize( void );  

3. xPortGetMinimumEverFreeHeapSize

作用:程序运行过程中,返回空闲内存容量的最小值,仅heap_4、heap_5支持

size_t xPortGetMinimumEverFreeHeapSize( void );  

4. malloc 失败的钩子函数

pvPortMallc函数内部,pvPortMallc失败时会调用此函数

使用时需要在FreeRTOSConfig.h 中,把configUSE_MALLOC_FAILED_HOOK 定义为1,并提供vApplicationMallocFailedHook 函数

void * pvPortMalloc( size_t xWantedSize )vPortDefineHeapRegions 
{ 
    ...... 
    #if ( configUSE_MALLOC_FAILED_HOOK == 1 ) 
    { 
        if( pvReturn == NULL ) 
        { 
        extern void vApplicationMallocFailedHook( void ); 
        vApplicationMallocFailedHook(); 
        } 
    } 
    #endif 
    return pvReturn;         
}   
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号