=============================== 博客点滴积累,部分话语和知识点来源于网络,感谢网络资源的提供者======
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;/*<< 下一个空闲块的指针 */} BlockLink_t;
size_t xBlockSize;/*<<空闲块的大小 最高bit为1 表示已经被分配,为0表示空闲 这是与heap2 有区别的地方*/
#if (SUPPORT_HEAP_DEBUG == 1)
TaskHandle_t xHandle;
#endif
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_tstructure 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();}
}}
/*-----------------------------------------------------------*/