码迷,mamicode.com
首页 > 其他好文 > 详细

FreeRTOS内存管理

时间:2019-01-16 23:57:02      阅读:378      评论:0      收藏:0      [点我收藏+]

标签:detail   epc   lru   uil   wrr   sed   mmx   let   函数   

heap1是FreeRTOS中内存管理最简单的一个,它简单到只能申请内存。是的,跟你想的一样,一旦申请成功后,这块内存再也无法释放。对于大多数嵌入式系统,特别是对安全要求高的嵌入式系统,这种内存管理策略很有用,因为对系统软件来说,逻辑越简单,越安全。实际上,大多数的嵌入式系统并不需要动态删除任务、信号量和队列等。而是在初始化的时候一次性创建,便一直存在,永不删除。
 
总结heap1特性如下:
    1、适用于那些一旦创建好任务、信号量和队列就再也不删除的的应用。
    2、具有可确定性(执行所花费的时间大多数一样),而且不会导致内存碎片。
    3、代码实现和内存分配过程都非常简单,内存是从一个静态数组中获取,也就是适用于那些不需要动态内存分配的应用。
 
我们可以将第一种内存管理看作切面包:初始化的静态数组就像一个完整的长棍面包,每次申请内存,就从一端切下适当长度的面包返还给申请者,直到面包被分配完毕。
 
heap1的内存管理策略使用两个静态变量来跟踪内存的使用,定义如下:
static size_t xNextFreeByte = ( size_t ) 0;
 
void *pvPortMalloc( size_t xWantedSize )
{
    static uint8_t *pucAlignedHeap = NULL;
    ...
}
其中 xNextFreeByte 用来保存 pucAlignedHeap  到内存堆剩余内存首地址之间的偏移值,如下图所示:
                                             技术分享图片
变量 xNextFreeByte  一开始初始化为0,每次成功申请内存后,都会增加申请内存的大小(对齐会导致实际申请的内存更多)。 变量 pucAlignedHeap 指向每次对齐后的内存堆首地址,内存对齐的好处是硬件访问数据只要单次读取,而且某些类型的内核不支持非对齐访问。STM32F0x系列的单片机要求16位对齐,非对齐读取会导致单片机进入HardFault.
 
内存申请函数:pvPortMalloc
 
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;
}

 

 
函数逻辑步骤:
    1、xWantedSizev 根据宏 portBYTE_ALIGNMENT (实验环境默认为4) 判断是否要字节对齐,调整 xWantedSize 为对齐字节数的倍数。 调整方法是,找到比 xWantedSize 大, 且是最靠近 xWantedSize  的对齐数。假设 xWantedSize 是11,经过调整后,结果为12。
    
    2、注意!内存申请的过程中禁止调度,不能被其他任务打断。FreeRTOS 使用 vTaskSuspendAll  和 xTaskResumeAll  禁止任务调度。
 
    3、不仅申请的内存块大小要求4字节对齐,内存堆的起始地址也必须是4字节对齐。pucAlignedHeapNULL的时候说明是第一次申请内存,需要初始化相关参数。ucHeap 此时的起始地址显然不是4字节的倍数,pucAlignedHeap  不能以ucHeap 的首地址作为内存堆的首地址, pucAlignedHeap 经过调整后变为 0x0041b14c, 以3字节的损失换来了起始地址的对齐。ucHeappucAlignedHeap 第一次初始化的状态如下图所示:
 
                           技术分享图片
    4、进行边界检查,查看内存堆是否足够本次分配,xNextFreeBytexWantedSize的和不能超出可供使用的内存边界。如果内存够分配且不会越界,那么即将申请到的内存首地址赋值给pReturn 并更新全局变量 xNextFreeByte特别说明的是实际可用的内存是 configADJUSTED_HEAP_SIZE 而不是configTOTAL_HEAP_SIZE。从代码中我们可以看出,FreeRTOS提前保留一部分字节供内存对齐使用
 
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE    ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )

 

                          技术分享图片技术分享图片
5、宏 configUSE_MALLOC_FAILED_HOOK  为1说明使能了内存申请失败钩子函数,在申请失败的情况下,会调用钩子函数 vApplicationMallocFailedHook ,这个钩子函数由用户应用程序提供,一般用来打印故障信息。
 
 
 参考文章:
 
 
 

FreeRTOS内存管理

标签:detail   epc   lru   uil   wrr   sed   mmx   let   函数   

原文地址:https://www.cnblogs.com/soga238/p/10280006.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!