FreeRTOS Heap Memory Management (5) - heap5源码分析

FreeRTOS Heap Memory Management (5) - heap5源码分析

/* FreeRTOS Kernel V10.4.1 */

原文链接:https://www.cnblogs.com/yanpio/p/14823117.html

heap5的实现与heap4除了内存初始化有所不同,其余部分几乎一致。

因此本文只分析初始化函数,其余部分详见FreeRTOS Heap Memory Management (4) - heap4源码分析

1 vPortDefineHeapRegions()

/* 定义非连续的内存分块 */
typedef struct HeapRegion
{
    uint8_t * pucStartAddress;
    size_t xSizeInBytes;
} HeapRegion_t;

/* 在调用pvPortMalloc()前,必须显示调用此函数来进行初始化 
 * 此函数的主要作用是将多个非连续的内存分块用链表串联在一起 */

/* 非连续内存块由数组进行描述,然后调用函数进行串联 */
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. */
};

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;

    /* 只初始化一次,多次调用则会卡在此处 */
    configASSERT( pxEnd == NULL );

    /* 从分块数组中取出第一个(xDefinedRegions = 0)进行处理 */
    pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );

    while( pxHeapRegion->xSizeInBytes > 0 )
    {
        xTotalRegionSize = pxHeapRegion->xSizeInBytes;

        /* 进行首部对齐. */
        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;

        /* xStart指向第一个内存分块的首部,所以仅在 xDefinedRegions == 0 的时候进行赋值  */
        if( xDefinedRegions == 0 )
        {
            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 );
        }

        /* 将pxEnd的值赋值给变量pxPreviousFreeBlock,如果是第一个内存分块,则此时pxPreviousFreeBlock = pxEnd = NULL. */
        pxPreviousFreeBlock = pxEnd;

        /* 内存分块尾部拿出一块存放pxEnd结构体,并做对齐处理 . */
        xAddress = xAlignedHeap + xTotalRegionSize;
        xAddress -= xHeapStructSize;
        xAddress &= ~portBYTE_ALIGNMENT_MASK;
        
        /* pxEnd指向内存分块的尾部 */
        pxEnd = ( BlockLink_t * ) xAddress;
        pxEnd->xBlockSize = 0;
        pxEnd->pxNextFreeBlock = NULL;

        /* 初始化内存分块的第一个block,占据内存分块的整个空间 */
        pxFirstFreeBlockInRegion = ( BlockLink_t * ) xAlignedHeap;
        pxFirstFreeBlockInRegion->xBlockSize = xAddress - ( size_t ) pxFirstFreeBlockInRegion;
        pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;

        /* 如果不是第一个内存分块,则将这个内存分块和上一个内存分块连接起来,连接过程见后文图示. */
        if( pxPreviousFreeBlock != NULL )
        {
            pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;
        }

        xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;

        /* 内存分块编号继续增加,继续处理下一个内存分块. */
        xDefinedRegions++;
        pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
    }

    xMinimumEverFreeBytesRemaining = xTotalHeapSize;
    xFreeBytesRemaining = xTotalHeapSize;

    /* Check something was actually defined before it is accessed. */
    configASSERT( xTotalHeapSize );

    /* 初始化变量. */
    xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}

2 说明

​ 上述连接内存分块的过程如下图所示:pxEnd指针不断迭代到新的内存分块的尾部,而之前的位置被替换成一个节点,xBlockSize = 0,并 指向下一个内存分块的第一个节点(首部)。如此串联,直到结束。

image-20210528164114095

posted on 2021-05-28 17:16  Yanpeng0527  阅读(187)  评论(0编辑  收藏  举报