FreeRTOS --(6)内存管理 heap5
转载自https://blog.csdn.net/zhoutaopower/article/details/106748308
FreeRTOS 中的 heap 5 内存管理,相对于 heap 4《FreeRTOS --(5)内存管理 heap4》 只增加了对非连续内存区域的管理,什么叫非连续区域内存呢?比如一款芯片,它即支持了内部的 RAM,也支持了外挂 RAM,那么这两个内存就可能在地址上不是连续的,比如 RAM1、RAM2、RAM3,如下所示:
针对这种情况,就可以使用 heap 5 来管理;
不同于之前的 heap 管理,heap 5 引入了一个结构体来管理这些非连续的区域:
typedef struct HeapRegion
{
/* The start address of a block of memory that will be part of the heap.*/
uint8_t *pucStartAddress;
/* The size of the block of memory in bytes. */
size_t xSizeInBytes;
} HeapRegion_t;
一个块连续的内存用一个 HeapRegion_t 表示,多个连续内存通过 HeapRegion_t 数组的形式组织成为了所有的内存;
heap 5 要求,在调用正式的内存分配函数之前,需要定义 HeapRegion,并调用 vPortDefineHeapRegions 来初始化它;
官方给了一个 demo:
/* Define the start address and size of the three RAM regions. */
#define RAM1_START_ADDRESS ( ( uint8_t * ) 0x00010000 )
#define RAM1_SIZE ( 65 * 1024 ) #define RAM2_START_ADDRESS ( ( uint8_t * ) 0x00020000 )
#define RAM2_SIZE ( 32 * 1024 ) #define RAM3_START_ADDRESS ( ( uint8_t * ) 0x00030000 )
#define RAM3_SIZE ( 32 * 1024 ) /* Create an array of HeapRegion_t definitions, with an index for each of the three
RAM regions, and terminating the array with a NULL address. The HeapRegion_t
structures must appear in start address order, with the structure that contains the
lowest start address appearing first. */
const HeapRegion_t xHeapRegions[] =
{
{ RAM1_START_ADDRESS, RAM1_SIZE },
{ RAM2_START_ADDRESS, RAM2_SIZE },
{ RAM3_START_ADDRESS, RAM3_SIZE },
{ NULL, 0 } /* Marks the end of the array. */
};
int main( void ) {
/* Initialize heap_5. */
vPortDefineHeapRegions( xHeapRegions );
/* Add application code here. */
}
如果有 3 个 RAM 区域的话,那么这样去定义他们;
需要注意的几点是:
1、定义 HeapRegion_t 数组的时候,最后一定要定义成为 NULL 和 0,这样接口才知道这是终点;
2、被定义的 RAM 区域,都会去参与内存管理;
那么问题就来了,在真实使用的时候,有可能你很难去定义部分 RAM 的 Start Address!
比如,一款芯片,它告诉你,它的第一块 RAM 有 64KB,第二块 RAM 有 32KB,第三块 RAM 有 32KB,那么你显然不能够直接将这些内存信息,按照上面 demo 代码的形式,定义到这个表格中,因为在编译阶段,有可能你相关的代码和数据等等(.text,.data,.bss,等)都会占用一部分的 RAM,但凡是定义到这个 HeapRegion_t 数组表格的,都会参与内存管理的行为,这显然是我们不愿意的;
也就是说,比如你芯片的 RAM 起始地址 0x2000_0000,你编译你的 Source Code 后,相关的代码和数据要占用 20KB,也就是 0x5000;那么你定义的 RAM1_START_ADDRESS 起始地址,就必须要大于 0x2000_0000+0x5000,这样才不会踩到你的其他数据;但是呢?你总不可能每次编译完都去改你的这个表吧?这是很痛苦的事情;
所有考虑到实际的使用,官方给出参考 demo 的方法是:
/* Define the start address and size of the two RAM regions not used by the
linker. */
#define RAM2_START_ADDRESS ( ( uint8_t * ) 0x00020000 )
#define RAM2_SIZE ( 32 * 1024 ) #define RAM3_START_ADDRESS ( ( uint8_t * ) 0x00030000 )
#define RAM3_SIZE ( 32 * 1024 ) /* Declare an array that will be part of the heap used by heap_5. The array will be
placed in RAM1 by the linker. */
#define RAM1_HEAP_SIZE ( 30 * 1024 ) static uint8_t ucHeap[ RAM1_HEAP_SIZE ]; /* Create an array of HeapRegion_t definitions. Whereas in Listing 6 the first entry
described all of RAM1, so heap_5 will have used all of RAM1, this time the first
entry only describes the ucHeap array, so heap_5 will only use the part of RAM1 that
contains the ucHeap array. The HeapRegion_t structures must still appear in start
address order, with the structure that contains the lowest start address appearing
first. */ const HeapRegion_t xHeapRegions[] =
{
{ ucHeap, RAM1_HEAP_SIZE },
{ RAM2_START_ADDRESS, RAM2_SIZE },
{ RAM3_START_ADDRESS, RAM3_SIZE },
{ NULL, 0 } /* Marks the end of the array. */
};
即,将链接的代码数据,根据链接器(Linker)配置后,这些都放置在第一段的区域,ucHeap 也放在一样的地方,这样就避免去根据 map 文件去硬编码这个表格;
通过 beyond compare 可以知道,heap 5 和 heap 4 的代码在分配内存的 pvPortMalloc,和释放内存的 vPortFree,以及插入节点合并空闲内存 prvInsertBlockIntoFreeList 的部分,几乎完全一样,唯一不一样的地方在于:
heap 4 的内存初始化用的是 prvHeapInit
heap 5 的内存初始化用的是 vPortDefineHeapRegions
那我们就来看看这个 vPortDefineHeapRegions 的实现:
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )
{
BlockLink_t *pxFirstFreeBlockInRegion = NULL, *pxPreviousFreeBlock;
size_t xAlignedHeap;
size_t xTotalRegionSize, xTotalHeapSize = 0;
BaseType_t xDefinedRegions = 0;
size_t xAddress;
const HeapRegion_t *pxHeapRegion; /* Can only call once! */
configASSERT( pxEnd == NULL ); pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] ); while( pxHeapRegion->xSizeInBytes > 0 )
{
xTotalRegionSize = pxHeapRegion->xSizeInBytes; /* Ensure the heap region starts on a correctly aligned boundary. */
xAddress = ( size_t ) pxHeapRegion->pucStartAddress;
if( ( xAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
xAddress += ( portBYTE_ALIGNMENT - 1 );
xAddress &= ~portBYTE_ALIGNMENT_MASK; /* Adjust the size for the bytes lost to alignment. */
xTotalRegionSize -= xAddress - ( size_t ) pxHeapRegion->pucStartAddress;
} xAlignedHeap = xAddress; /* Set xStart if it has not already been set. */
if( xDefinedRegions == 0 )
{
/* xStart is used to hold a pointer to the first item in the list of
free blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( BlockLink_t * ) xAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
}
else
{
/* Should only get here if one region has already been added to the
heap. */
configASSERT( pxEnd != NULL ); /* Check blocks are passed in with increasing start addresses. */
configASSERT( xAddress > ( size_t ) pxEnd );
} /* Remember the location of the end marker in the previous region, if
any. */
pxPreviousFreeBlock = pxEnd; /* pxEnd is used to mark the end of the list of free blocks and is
inserted at the end of the region space. */
xAddress = xAlignedHeap + xTotalRegionSize;
xAddress -= xHeapStructSize;
xAddress &= ~portBYTE_ALIGNMENT_MASK;
pxEnd = ( BlockLink_t * ) xAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL; /* To start with there is a single free block in this region that is
sized to take up the entire heap region minus the space taken by the
free block structure. */
pxFirstFreeBlockInRegion = ( BlockLink_t * ) xAlignedHeap;
pxFirstFreeBlockInRegion->xBlockSize = xAddress - ( size_t ) pxFirstFreeBlockInRegion;
pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd; /* If this is not the first region that makes up the entire heap space
then link the previous region to this region. */
if( pxPreviousFreeBlock != NULL )
{
pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;
} xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; /* Move onto the next HeapRegion_t structure. */
xDefinedRegions++;
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
} xMinimumEverFreeBytesRemaining = xTotalHeapSize;
xFreeBytesRemaining = xTotalHeapSize; /* Check something was actually defined before it is accessed. */
configASSERT( xTotalHeapSize ); /* Work out the position of the top bit in a size_t variable. */
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}
经过一些对齐操作,将 demo 中的 3 块内存通过链表的方式挂接起来了,只不过内存地址不连续而已,但是对于连续的内存地址中,照样在释放的时候,可以进行合并操作;
FreeRTOS --(6)内存管理 heap5的更多相关文章
- 轻量级操作系统FreeRTOS的内存管理机制(一)
本文由嵌入式企鹅圈原创团队成员朱衡德(Hunter_Zhu)供稿. 近几年来,FreeRTOS在嵌入式操作系统排行榜中一直位居前列,作为开源的嵌入式操作系统之一,它支持许多不同架构的处理器以及多种编译 ...
- FreeRTOS 动态内存管理
以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 动态内存管理,动态内存管理是 FreeRTOS 非常重要的一项功能,前面 ...
- FreeRTOS的内存管理
FreeRTOS提供了几个内存堆管理方案,有复杂的也有简单的.其中最简单的管理策略也能满足很多应用的要求,比如对安全要求高的应用,这些应用根本不允许动态内存分配的. FreeRTOS也允许你自己实现内 ...
- freertos之内存管理
任务.信号量.邮箱才调度器开始调度之前就应该创建,所以它不可能像裸奔程序那样的函数调用能确定需要多少内存资源,RTOS提供了3种内存管理的方法: 1 方法一:确定性好适合于任务.信号量.队列都不被删除 ...
- FreeRTOS内存管理
简介 Freertos的内存管理分别在heap_1.c,heap_2.c,heap_3.c,heap_4.c,heap_5.c个文件中,选择合适的一种应用于嵌入式项目中即可. 本文的图片中 红色部分B ...
- FreeRTOS --(3)内存管理 heap2
在<FreeRTOS --(2)内存管理 heap1>知道 heap 1 的内存管理其实只是简单的实现了内存对齐的分配策略,heap 2 的实现策略相比 heap 1 稍微复杂一点,不仅仅 ...
- FreeRTOS --(2)内存管理 heap1
转载自https://blog.csdn.net/zhoutaopower/article/details/106631237 FreeRTOS 提供了5种内存堆管理方案,分别对应heap1/heap ...
- FreeRTOS --(5)内存管理 heap4
FreeRTOS 中的 heap 4 内存管理,可以算是 heap 2 的增强版本,在 <FreeRTOS --(3)内存管理 heap2>中,我们可以看到,每次内存分配后都会产生一个内存 ...
- FreeRTOS--堆内存管理
因为项目需要,最近开始学习FreeRTOS,一开始有些紧张,因为两个星期之前对于FreeRTOS的熟悉度几乎为零,经过对FreeRTOS官网的例子程序的摸索,和项目中问题的解决,遇到了很多熟悉的身影, ...
随机推荐
- elasticsearch 5.6.7在线安装ik分词,亲测有效
官网的在线安装命令 ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/rele ...
- Python - time标准库使用与程序计时
- ACM中的位运算技巧
听说位运算挺好玩的,那这节总结一下ACM中可能用到的位运算技巧. XOR运算极为重要!!(过[LC136](只出现一次的数字 - 力扣(LeetCode)):数组中每个数字都出现两次,只有一个出现一次 ...
- 记MyBaits-Plus 实现菜单的无限层关系
Mybatis-Plus父子菜单 首先来看一下实现的效果 pojo层 @Data @TableName("platform_role") public class Role imp ...
- 如何0代码实现多人音视频通话?【内附源码/Demo】
3月15日新增"1860+1194",全国进入了抗疫关键时期.响应政策多地采取了社会面清零策略. 3月14日零点,深圳按下了暂停键. 应疫情防控要求,深圳全市暂停生产经营活动,严格 ...
- GoLang数组切片
1. 数组1.1 如何定义数组同java数组一样,数组是一组内存连续且类型相同的数据组成 //不初始化初始值默认为0 var arr1 = [5]int{} var arr2 = [5]int{1,2 ...
- CSS3渐变效果工具
推荐一个css3渐变效果工具,觉得有帮助的可以收藏下. 工具链接 CSS3 渐变(gradients)可以让你在两个或多个指定的颜色之间显示平稳的过渡.CSS3 定义了两种类型的渐变(gradient ...
- 基于vue2.0的在线电影APP,
基于vue2.0构建的在线电影网[film],webpack + vue + vuex + vue-loader + keepAlive + muse-ui + cordova 全家桶,cordova ...
- fetch,终于认识你
fetch和XMLHttpRequest 如果看网上的fetch教程,会首先对比XMLHttpRequest和fetch的优劣,然后引出一堆看了很快会忘记的内容(本人记性不好).因此,我写一篇关于fe ...
- 【uniapp 开发】日期工具类 -- DateUtil
日期格式转毫秒值 var time = '2019-08-08 12:09:34'; var time222 = time.replace("-", "/"). ...