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
,并 指向下一个内存分块的第一个节点(首部)。如此串联,直到结束。