FreeRtos heap4源码分析

===============================   博客点滴积累,部分话语和知识点来源于网络,感谢网络资源的提供者======

heap4 与heap2 比较相似,也是简单地实现了pvPortMalloc()和vPortFree(),不过对于释放的空闲内存碎片进行了合并,其他的细微区别会在代码说明的,这里只贴与heap2 不一样的地方

/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/*结合宏heapBITS_PER_BYTE 标记结构体A_BLOCK_LINK的xBlockSize最高位*/
static size_t xBlockAllocatedBit = 0;
/* 定义一个链表结构体,存空闲的内存块指针和大小 */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK *pxNextFreeBlock;/*<< 下一个空闲块的指针 */
size_t xBlockSize;/*<<空闲块的大小 最高bit为1 表示已经被分配,为0表示空闲 这是与heap2 有区别的地方*/
#if (SUPPORT_HEAP_DEBUG == 1)
TaskHandle_t xHandle;
#endif
} BlockLink_t;
static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
uint32_t ulAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
ulAddress = ( uint32_t ) ucHeap;
if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{//调整使其字节对齐,向上取整
ulAddress += ( portBYTE_ALIGNMENT - 1 );
ulAddress &= ~portBYTE_ALIGNMENT_MASK;
xTotalHeapSize -= ulAddress - ( uint32_t ) ucHeap;
}
pucAlignedHeap = ( uint8_t * ) ulAddress;
/* 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 = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/*这一块和heap2有点区别了,heap2 pxEnd 是一个结构体,heap4时,是一个结构体指针
指向ulAddress,这个地址存着pxEnd 结构体*/
ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalHeapSize;
ulAddress -= xHeapStructSize;
ulAddress &= ~portBYTE_ALIGNMENT_MASK;
pxEnd = ( void * ) ulAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* To start with there is a single free block that is sized to take up the
entire heap space, minus the space taken by pxEnd. */
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlock;//结束地址-开始地址= 大小
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
#if (SUPPORT_HEAP_DEBUG == 1)
pxFirstBlock = pxFirstFreeBlock;
#endif
/* Only one block exists - and it covers the entire usable heap space. */
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;

/*设置xBlockAllocatedBit 最高位为1 将来标记内存块是否被分配过*/
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}
/*-----------------------------------------------------------*/
/*heap4 与heap2 最大的区别就是这个函数了,插入时,会合并内存碎片*/
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
{
BlockLink_t *pxIterator;
uint8_t *puc;
/*遍历查找到,内存块地址大于插入块地址,就跳出*/
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
{
/* Nothing to do here, just iterate to the right position. */
}
/* Do the block being inserted, and the block it is being inserted after
make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{//前一块和插入块相邻,合并内存块
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{//后一块和插入块相邻,合并内存块
if( pxIterator->pxNextFreeBlock != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
/* 如果和前一块内存合并了, 内存地址会相等,不用修改指针,若不相等,则需要修改指针插入*/
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/

void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
vTaskSuspendAll();
{
/* 如果是第一次初始化,需要初始化空闲链表. */
if( pxEnd == NULL )
{
prvHeapInit();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 需要分配的内存不能太大 */
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
{
/* The wanted size is increased so it can contain a BlockLink_t
structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += xHeapStructSize;/*分配的地址最前面放这个BlockLink_t结构体*/
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{/* 调整字节对齐 */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* /*空闲块是从小到大存储,遍历链表,直到找到合适的空闲块 */ */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{/* 如果该空闲块比较大,剩余的大小大于两个BlockLink_t,则将该块分为两个 */
/* 创建一个新块*/
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
configASSERT( ( ( ( uint32_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
/* 计算新块的大小*/
/* If the end marker was reached then a block of adequate size wasnot found. */
if( pxBlock != pxEnd )
{/* 遍历后找到合适的块 */
/* 返回分配的内存地址 - 分配的地址实际是BlockLink_t + 需要分配的大小,所以返回的地址要跳过BlockLink_t */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
#if (SUPPORT_HEAP_DEBUG == 1)
pxPreviousBlock->pxNextFreeBlock->xHandle = xTaskGetCurrentTaskHandle();
#endif

/* 去掉空闲链表的刚分配的块 */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;

/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xFreeBytesRemaining -= pxBlock->xBlockSize;//减去已经分配的字节数,剩下实际可分配的字节数
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 标记该内存块已经被分配,并置pxBlock->pxNextFreeBlock = NULL */
pxBlock->xBlockSize |= xBlockAllocatedBit;
pxBlock->pxNextFreeBlock = NULL;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();

#if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
configASSERT( ( ( ( uint32_t ) pvReturn ) & portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;
if( pv != NULL )
{
/* 分配的大小是 实际大小 + heapSTRUCT_SIZE 所以实际的起始地址需要减去heapSTRUCT_SIZE */
puc -= xHeapStructSize;
pxLink = ( void * ) puc;
/* Check the block is actually allocated. */
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
/*被分配的地址,xBlockSize 最高bit为1*/
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )/*被分配后pxLink->pxNextFreeBlock 被置位NULL*/
{
/* 修改标志,表示该内存块空闲 */
pxLink->xBlockSize &= ~xBlockAllocatedBit;
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值