FreeRTOS--堆內存管理(二)

堆內存管理代碼具體實現

  • heap_1
    • 內存申請函數
    • 內存釋放函數
  • heap_2
    • 內存塊
    • 內存堆初始化函數
    • 內存塊插入函數
    • 內存申請函數
      • 判斷是不是第一次申請內存
      • 開始分配內存
      • 內存釋放函數
  • heap_3
  • heap_4
    • 內存堆初始化函數
    • 內存塊插入函數
  • heap_5

上一篇文章說了FreeRTOS實現堆內存的原理,這一篇文章說一下常用函數的代碼的具體實現。

heap_1

heap_1的內存堆為ucHeap[],大小為configTOTAL_HEAP_SIZE

內存申請函數

heap_1的內存申請函數pvPortMalloc()源碼如下:

/*-----------------------------------------------------------*/void * pvPortMalloc( size_t xWantedSize )
{void * pvReturn = NULL;static uint8_t * pucAlignedHeap = NULL;/* Ensure that blocks are always aligned. */#if ( portBYTE_ALIGNMENT != 1 ){if( xWantedSize & portBYTE_ALIGNMENT_MASK ){/* Byte alignment required. Check for overflow. */if ( (xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) )) > xWantedSize ){xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );}else{xWantedSize = 0;}}}#endifvTaskSuspendAll();{if( pucAlignedHeap == NULL ){/* Ensure the heap starts on a correctly aligned boundary. */pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );}/* Check there is enough room left for the allocation and. */if( ( xWantedSize > 0 ) && /* valid size */( ( 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();}}#endifreturn pvReturn;
}
/*-----------------------------------------------------------*/

下面的代碼塊是判斷內存塊是否對齊

void * pvPortMalloc( size_t xWantedSize )
{void * pvReturn = NULL;static uint8_t * pucAlignedHeap = NULL;/* Ensure that blocks are always aligned. */#if ( portBYTE_ALIGNMENT != 1 ){if( xWantedSize & portBYTE_ALIGNMENT_MASK ) /***** 令  length = portBYTE_ALIGNMENT_MASK二進制中1的個數*       x = xWantedSize的后length位的值*       y = portBYTE_ALIGNMENT_MASK-x+1*   如果 xWantedSize & portBYTE_ALIGNMENT_MASK = 0,則xWantedSize肯定是(portBYTE_ALIGNMENT_MASK+1)的整數倍*   如果  xWantedSize & portBYTE_ALIGNMENT_MASK不為0,則xWantedSize的后length位肯定有1,xWantedSize不是portBYTE_ALIGNMENT_MASK的整數倍*   如果 xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) )大于xWantedSize,說明后length位肯定有1*   xWantedSize = xWantedSize + y,xWantedSize變成portBYTE_ALIGNMENT整數倍******/{/* Byte alignment required. Check for overflow. */if ( (xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) )) > xWantedSize ){xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );}else{xWantedSize = 0;}}}#endif

#if ( portBYTE_ALIGNMENT != 1 )是判斷是否進行字節對齊,portBYTE_ALIGNMENT默認為8:
在這里插入圖片描述

#if portBYTE_ALIGNMENT == 32#define portBYTE_ALIGNMENT_MASK    ( 0x001f )
#elif portBYTE_ALIGNMENT == 16#define portBYTE_ALIGNMENT_MASK    ( 0x000f )
#elif portBYTE_ALIGNMENT == 8#define portBYTE_ALIGNMENT_MASK    ( 0x0007 )
#elif portBYTE_ALIGNMENT == 4#define portBYTE_ALIGNMENT_MASK    ( 0x0003 )
#elif portBYTE_ALIGNMENT == 2#define portBYTE_ALIGNMENT_MASK    ( 0x0001 )
#elif portBYTE_ALIGNMENT == 1#define portBYTE_ALIGNMENT_MASK    ( 0x0000 )
#else /* if portBYTE_ALIGNMENT == 32 */#error "Invalid portBYTE_ALIGNMENT definition"

因為portBYTE_ALIGNMENT 定義為8,所以portBYTE_ALIGNMENT_MASK 定義為0x0007,xWantedSize 是無符號整數類型(unsigned int),即32位,xWantedSize 與宏portBYTE_ALIGNMENT_MASK 進行與運算來判斷xWantedSize是否為portBYTE_ALIGNMENT 的整數倍,如果等于0就說明xWantedSizr是portBYTE_ALIGNMENT 的整數倍,否則的話將xWantedSize加上一個值,讓xWantedSize 變成portBYTE_ALIGNMENT 的整數倍。具體可以看一下代碼,我加了注釋。
調用vTaskSuspendAll()掛起任務調度器,因為申請內存過程中要做保護,不能被其他任務打斷。

pucAlignedHeap是一個靜態變量,下面這個代碼是初試化pucAlignedHeap,pucAlignedHeap指向ucHeap[ portBYTE_ALIGNMENT - 1 ]

if( pucAlignedHeap == NULL ){/* Ensure the heap starts on a correctly aligned boundary. *//**** 初始化pucAlignedHeap,pucAlignedHeap指向ucHeap[ portBYTE_ALIGNMENT - 1 ]**/pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );}

接下來就是分配內存了,最后返回pvReturn,是分配內存的首地址,其中xNextFreeByte是靜態變量,表示堆ucHeap已經用了多少內存,configADJUSTED_HEAP_SIZE= configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT,是可以用的內存容量。還有如果剩余內存小于portBYTE_ALIGNMENT,也是不會創建成功的,也就說是,最后的堆可能有內存碎片,下面也一樣。

內存釋放函數

void vPortInitialiseBlocks( void )
{/* Only required when static memory is not cleared. */xNextFreeByte = ( size_t ) 0;
}

可以看出vPortFree并沒有具體釋放內存的過程,因此如果使用heap_1,一旦申請內存成功就不允許釋放。

heap_2

heap_2的內存堆為ucHeap[],大小為configTOTAL_HEAP_SIZE

內存塊

為了實現內存釋放,heap_2引入內存塊的概念,每分出去的一段內存就是內存塊,為了管理內存塊,引入了一個鏈表結構,此鏈表是來連接空閑塊的,鏈表中的空閑塊順序是根據空閑塊內存的大小排列,鏈表結構如下:

/* Define the linked list structure.  This is used to link free blocks in order* of their size. */
typedef struct A_BLOCK_LINK
{struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */size_t xBlockSize;                     /*<< The size of the free block. */
} BlockLink_t;

為了管理該列表,FreeRTOS定義兩個靜態變量,xStart、xEnd分別指向鏈表的頭和尾:

/* Create a couple of list links to mark the start and end of the list. */
static BlockLink_t xStart, xEnd;

內存堆初始化函數

內存堆初始化函數為pvHeapInit()

static void prvHeapInit( void )
{BlockLink_t * pxFirstFreeBlock;uint8_t * pucAlignedHeap;/* Ensure the heap starts on a correctly aligned boundary. */pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );/* 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;/* xEnd is used to mark the end of the list of free blocks. */xEnd.xBlockSize = configADJUSTED_HEAP_SIZE;xEnd.pxNextFreeBlock = NULL;/* To start with there is a single free block that is sized to take up the* entire heap space. */pxFirstFreeBlock = ( void * ) pucAlignedHeap;pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE;pxFirstFreeBlock->pxNextFreeBlock = &xEnd;
}

同heap_1一樣,pucAlignedHeap指向ucHeap[ portBYTE_ALIGNMENT - 1 ],xStart.pxNextFreeBlock指向pucAlignedHeap ,內存塊大小為0,xEnd指向的內存塊大小為configADJUSTED_HEAP_SIZE,pxNextFreeBlock 的值為NULL,第一個內存塊pxFirstFreeBlock 指向pucAlignedHeap,大小為configADJUSTED_HEAP_SIZE,pxNextFreeBlock 指向xEnd。

內存塊插入函數

#define prvInsertBlockIntoFreeList( pxBlockToInsert )                                                                               \{                                                                                                                               \BlockLink_t * pxIterator;                                                                                                   \size_t xBlockSize;                                                                                                          \\xBlockSize = pxBlockToInsert->xBlockSize;                                                                                   \\/* Iterate through the list until a block is found that has a larger size */                                                \/* than the block we are inserting. */                                                                                      \for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \{                                                                                                                           \/* There is nothing to do here - just iterate to the correct position. */                                               \}                                                                                                                           \\/* Update the list to include the block being inserted in the correct */                                                    \/* position. */                                                                                                             \pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;                                                             \pxIterator->pxNextFreeBlock = pxBlockToInsert;                                                                              \}

就是在一個排好序的鏈表中插入一個數據,xStart最小,for循環一直找到鏈表中空閑內存塊大于pxBlockToInsert內存塊大小的內存塊,然后插入進去

內存申請函數

void * pvPortMalloc( size_t xWantedSize )
{BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;static BaseType_t xHeapHasBeenInitialised = pdFALSE;void * pvReturn = NULL;vTaskSuspendAll();{/* If this is the first call to malloc then the heap will require* initialisation to setup the list of free blocks. */if( xHeapHasBeenInitialised == pdFALSE ){prvHeapInit();xHeapHasBeenInitialised = pdTRUE;}/* The wanted size must be increased so it can contain a BlockLink_t* structure in addition to the requested amount of bytes. */if( ( xWantedSize > 0 ) &&( ( xWantedSize + heapSTRUCT_SIZE ) >  xWantedSize ) ) /* Overflow check */{xWantedSize += heapSTRUCT_SIZE;/* Byte alignment required. Check for overflow. */if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) )> xWantedSize ){xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );}else{xWantedSize = 0;}}else{xWantedSize = 0;}if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ){/* Blocks are stored in byte order - traverse the list from the start* (smallest) block until one of adequate size is found. */pxPreviousBlock = &xStart;pxBlock = xStart.pxNextFreeBlock;while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ){pxPreviousBlock = pxBlock;pxBlock = pxBlock->pxNextFreeBlock;}/* If we found the end marker then a block of adequate size was not found. */if( pxBlock != &xEnd ){/* Return the memory space - jumping over the BlockLink_t structure* at its start. */pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );/* This block is being returned for use so must be taken out of the* list of free blocks. */pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;/* If the block is larger than required it can be split into two. */if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ){/* This block is to be split into two.  Create a new block* following the number of bytes requested. The void cast is* used to prevent byte alignment warnings from the compiler. */pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );/* Calculate the sizes of two blocks split from the single* block. */pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;pxBlock->xBlockSize = xWantedSize;/* Insert the new block into the list of free blocks. */prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );}xFreeBytesRemaining -= pxBlock->xBlockSize;}}traceMALLOC( pvReturn, xWantedSize );}( void ) xTaskResumeAll();#if ( configUSE_MALLOC_FAILED_HOOK == 1 ){if( pvReturn == NULL ){extern void vApplicationMallocFailedHook( void );vApplicationMallocFailedHook();}}#endifreturn pvReturn;
}

判斷是不是第一次申請內存

xHeapHasBeenInitialised是一個靜態變量,初始值為pdFALSE,根據xHeapHasBeenInitialised判斷是不是第一個調用pvPortMalloc,如果是,即xHeapHasBeenInitialised=pdFALSE,則調用初始化函數prvHeapInit(),然后將xHeapHasBeenInitialised設置為pdTRRE。

開始分配內存

判斷xWantedSize是否大于0,不是的話則xWantedSize=0。在大于0 的情況下,xWantedSize要加上heapSTRUCT_SIZE,heapSTRUCT_SIZE是一個static const類型,值為8,是為了來存儲一個BlockLink_t結構,同樣分配的內存大小也必須是portBYTE_ALIGNMENT的整數倍。

 if( ( xWantedSize > 0 ) &&( ( xWantedSize + heapSTRUCT_SIZE ) >  xWantedSize ) ) /* Overflow check */{xWantedSize += heapSTRUCT_SIZE;/* Byte alignment required. Check for overflow. */if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) )> xWantedSize ){xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );}else{xWantedSize = 0;}}

如果xWantedSize>0并且xWantedSize要小于xFreeBytesRemaining,xFreeBytesRemaining是一個靜態類型變量,表示剩下的可用字節數(所有空閑塊大小之和)。
接著按照空閑塊大小,從小到大,依次遍歷,直到找到一個空閑塊,其大小大于等于xWantedSize(此時的xWantedSize=一開始請求的xWantedSize+sizeof(BlockLink_t)),找到滿足所需內存塊pxBlock,pxPreviousBlock的pxPreviousBlock就指向pxBlock,如果pxBlock不是指向xEnd,就分配內存,pvReturn指向 (pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize的地址,跳過了BlockLink_t,如果pxBlock剩余的內存大于secureheapMINIMUM_BLOCK_SIZE,則將剩余的內存設置成一個新的空閑內存塊,新的空閑內存塊用 pxNewBlockLink 表示,pxNewBlockLink指向新的內存塊的首地址,接著調用prvInsertBlockIntoFreeList,將pxNewBlockLink插入到空閑鏈表中。

 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;/* Ensure that blocks are always aligned to the required number of* bytes. */if( ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) != 0x00 ){/* Byte alignment required. */xWantedSize += ( secureportBYTE_ALIGNMENT - ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) );secureportASSERT( ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) == 0 );}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ){/* Traverse the list from the start (lowest address) block until* one of adequate size is found. */pxPreviousBlock = &xStart;pxBlock = xStart.pxNextFreeBlock;while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ){pxPreviousBlock = pxBlock;pxBlock = pxBlock->pxNextFreeBlock;}/* If the end marker was reached then a block of adequate size was* not found. */if( pxBlock != pxEnd ){/* Return the memory space pointed to - jumping over the* BlockLink_t structure at its start. */pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );/* This block is being returned for use so must be taken out* of the list of free blocks. */pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;/* If the block is larger than required it can be split into* two. */if( ( pxBlock->xBlockSize - xWantedSize ) > secureheapMINIMUM_BLOCK_SIZE ){/* This block is to be split into two.  Create a new* block following the number of bytes requested. The void* cast is used to prevent byte alignment warnings from the* compiler. */pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );secureportASSERT( ( ( ( size_t ) pxNewBlockLink ) & secureportBYTE_ALIGNMENT_MASK ) == 0 );/* Calculate the sizes of two blocks split from the single* block. */pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;pxBlock->xBlockSize = xWantedSize;/* Insert the new block into the list of free blocks. */prvInsertBlockIntoFreeList( pxNewBlockLink );}

接著更新xFreeBytesRemaining,xBlockSize=請求的xWantedSize+sizeof(BlockLink_t)

 xFreeBytesRemaining -= pxBlock->xBlockSize;

最后如果使用hook函數,就調用vApplicationMallocFailedHook()

內存釋放函數

void vPortFree( void * pv )
{uint8_t * puc = ( uint8_t * ) pv;BlockLink_t * pxLink;if( pv != NULL ){/* The memory being freed will have an BlockLink_t structure immediately* before it. */puc -= heapSTRUCT_SIZE;/* This unexpected casting is to keep some compilers from issuing* byte alignment warnings. */pxLink = ( void * ) puc;vTaskSuspendAll();{/* Add this block to the list of free blocks. */prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );xFreeBytesRemaining += pxLink->xBlockSize;traceFREE( pv, pxLink->xBlockSize );}( void ) xTaskResumeAll();}
}

puc為要釋放的內存首地址,這就是申請內存返回的pvReturn所指向的地址,所以必須減去heapSTRUCT_SIZE才是要釋放的內存段所在內存塊的首地址。pxLink 指向真正的釋放的內存首地址,將pxLink插入到空閑塊鏈表中,更新xFreeBytesRemaining 。

heap_3

這個分配方法是對標準C庫中的mallco和free函數簡單封裝,FreeRTOS對這兩個函數做了線程保護,不分析了。

heap_4

heap_4提供了最優的匹配算法,并且會將碎片合并成一個大的可用內存塊,它提供了內存塊合并算法

內存堆初始化函數

static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
{BlockLink_t * pxFirstFreeBlock;uint8_t * pucAlignedHeap;size_t uxAddress;size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;/* Ensure the heap starts on a correctly aligned boundary. */uxAddress = ( size_t ) ucHeap;if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 ){uxAddress += ( portBYTE_ALIGNMENT - 1 );uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;}pucAlignedHeap = ( uint8_t * ) uxAddress;/* 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;/* pxEnd is used to mark the end of the list of free blocks and is inserted* at the end of the heap space. */uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;uxAddress -= xHeapStructSize;uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );pxEnd = ( void * ) uxAddress;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 = uxAddress - ( size_t ) pxFirstFreeBlock;pxFirstFreeBlock->pxNextFreeBlock = pxEnd;/* Only one block exists - and it covers the entire usable heap space. */xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;/* Work out the position of the top bit in a size_t variable. */xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}

首先對申請的內存做字節對齊處理,pucAlignedHeap 為內存堆字節對齊以后的可用起始地址,初始化xStart、pxEnd,同heap_2一樣,內存塊前面會有一個BlockLink_t類型的變量來描述內存塊,這里是完成pxFirstFreeBlock 的初始化,xMinimumEverFreeBytesRemaining 記錄最小的空閑內存塊大小,xFreeBytesRemaining 表示內存堆剩余大小,初始化靜態變量xBlockAllocatedBit

內存塊插入函數

static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
{BlockLink_t * pxIterator;uint8_t * puc;/* Iterate through the list until a block is found that has a higher address* than the block being inserted. */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();}/* Do the block being inserted, and the block it is being inserted before* make a contiguous block of memory? */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 the block being inserted plugged a gab, so was merged with the block* before and the block after, then it's pxNextFreeBlock pointer will have* already been set, and should not be set here as that would make it point* to itself. */if( pxIterator != pxBlockToInsert ){pxIterator->pxNextFreeBlock = pxBlockToInsert;}else{mtCOVERAGE_TEST_MARKER();}
}

下面的代碼是遍歷空閑內存塊鏈表,找出當前內存塊插入點,內存塊是按照地址從低到高的順序鏈接在一起

   for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ){/* Nothing to do here, just iterate to the right position. */}

找到插入點以后判斷是否可以和要插入的內存塊合并,如果可以的話就合并在一起,接著檢查是否可以和下一個內存塊合并,如果可以就再次合并,如果不能就將這兩個內存塊連接起來,pxIterator不等于pxBlockToInsert就意味著在內存塊插入的過程中 沒有進行過一次內存合并這樣的話就使用最普通的處理方法,pxIterator所指向的內存塊在前,pxBlockToinsert所指向的內存塊在后,將兩個內存塊鏈接起來。

heap_5

heap_5 使用了和heap_4相同的合并算法,內存管理實現起來基本相同,但是heap_5內存堆跨越多個不連續的內存段,在使用heap_5調用API函數之前需要調用vPortDefineHeapRegions來對內存做初始化處理,在vPortDefineHeapRegions未執行之前禁止調用任何可能會調用pvPortMalloc的API函數。vPortDefineHeapRegions的參數是一個HeapRegion_t類型的數組,HeapRegion是一個結構體:

typedef struct HeapRegion
{uint8_t * pucStartAddress;	//內存塊的起始地址	size_t xSizeInBytes;	//內存段大小
} HeapRegion_t;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379703.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379703.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379703.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在查詢的結果中添加自增列 兩種方法

解決辦法《一》&#xff1a; 在SQL Server數據庫中表信息會用到Identity關鍵字來設置自增列。但是當有數據被刪除的話&#xff0c;自增列就不連續了。如果想查詢出這個表的信息&#xff0c;并添 加一列連續自增的ID&#xff0c;可用如下查詢語句&#xff1a; SELECT Row_Nu…

一個非常簡單的C#面試題

怎樣實現對所有類可讀但是在同一個assembly可寫那&#xff1f; 答案&#xff1a; 同一個assembly namespace ClassLibrary1 { public class Class1 { public string Name { get; internal set; } } public class Class2 { public void GS() { Class1 cc new Class1(); cc.Name…

css中的node.js_在Node App中使用基本HTML,CSS和JavaScript

css中的node.jsYou may think this is not important, but it is!. As a beginner in node.js, most coding exercises are always server sided. 您可能認為這并不重要&#xff0c;但確實如此&#xff01; 作為node.js的初學者&#xff0c;大多數編碼練習始終都是服務器端的。…

Binary String Matching(C++)

題目描述: Given two strings A and B, whose alphabet consist only ‘0’ and ‘1’. Your task is only to tell how many times does A appear as a substring of B? For example, the text string B is ‘1001110110’ while the pattern string A is ‘11’, you should…

由一次代碼優化想到的Js 數據類型

引子&#xff1a; 上周三進行了代碼優化&#xff0c;其中有一個很普遍的代碼&#xff0c;例如&#xff1a; if(test "") {dothis();}else{dothat()} ----->可以簡化為 !test ? dothis():dothat(); if(test "") {dothis()}     ----->可以簡化為…

VisualStudio2019配置OpenCV

VisualStudio2019配置OpenCV配置0x01 準備0x02 配置系統環境0x03 復制文件0x04 配置VisualStudio2019測試配置 0x01 準備 下載opencv&#xff0c;官網地址&#xff1a;https://opencv.org/releases/# 下載之后&#xff0c;自行安裝 0x02 配置系統環境 找到高級系統設置 …

轉載 Javascript的IE和Firefox兼容性匯編

微軟關于IE、Firefox、Opera和Safari的JavaScript兼容性研究曾經發表過一份草案,可以點擊下載《JScript Deviations from ES3》 以下為網上的一些搜集和整理(FF代表Firefox) 集合類對象問題現有代碼中存在許多 document.form.item("itemName") 這樣的語句&#xff0c…

存儲器間接尋址方式_8086微處理器的程序存儲器尋址模式

存儲器間接尋址方式The Program Memory Addressing mode is used in branch instructions. These branch instructions are instructions which are responsible for changing the regular flow of the instruction execution and shifting the control to some other location…

Servlet的配置

1&#xff0c;基本配置 <!-- Servlet類的配置 --><servlet><servlet-name>sq</servlet-name><servlet-class>beyond.servlet.QuickStartServlet</servlet-class></servlet><!-- Servlet的虛擬路徑的配置 --> <servlet-mapp…

Asp.net頁面生存周期

# 事件或方法 功能 描述   1 Init 事件 頁面初始化 初始化設置。   2 LoadViewState 方法 加載視圖狀態 填充ViewState屬性。   3 LoadPostData 方法 處理回發數據 處理傳入窗體數據。   4 Load 事件 加載頁面 頁面控件初始化完成并反映了客戶端的數據。   5 RaisePo…

你正確關閉WCF鏈接了嗎?

通常情況下我們關閉一個WCF鏈接都是簡單地寫把ICommunicationObject.Close()方法&#xff0c;但是這個方法有個問題就是當調用發生異常時&#xff0c;Close()會發生次生的異常&#xff0c;導致鏈接不能正常關閉。如果當這種異常很多時&#xff0c;必然對系統的穩定性有很大的影…

Visual Studio進行linux遠程開發

目錄準備工作創建一個項目配置遠程項目準備工作 查看linux IP地址 安裝了工具 sudo apt-get install openssh-server g gdb make ninja-build rsync zip開啟ssh服務&#xff1a; sudo service ssh startVS2019按裝了linux功能&#xff0c;如果沒有&#xff0c;找到Visual S…

在給定總和K的二叉樹中找到級別

Description: 描述&#xff1a; The article describes how to find the level in a binary tree with given sum K? This is an interview coding problem came in Samsung, Microsoft. 本文介紹了如何在給定總和K下在二叉樹中找到級別 &#xff1f; 這是一個面試編碼問題&a…

PostgreSQL學習手冊(數據庫維護) 轉

原文&#xff1a; PostgreSQL學習手冊(數據庫維護)一、恢復磁盤空間&#xff1a;在PostgreSQL中&#xff0c;使用delete和update語句刪除或更新的數據行并沒有被實際刪除&#xff0c;而只是在舊版本數據行的物理地址上將該行的狀態置為已刪除或已過期。因此當數據表中的數據變化…

++i與i++的根本性區別(兩個代碼對比搞定)

首先來看i 代碼如下&#xff1a; #include <stdio.h> #include <stdlib.h> int main() {int i0;int ai;printf("%d\n",a);printf("%d\n\n\n",i);return 0; }輸出結果如下&#xff1a; 解釋&#xff1a;i其實是兩行代碼的簡寫形式&#xff0c…

國企和外企的比較

由于本人在外企&#xff0c;而很多朋友在國企&#xff0c;因此我個人的說法應該還是有一定的權威性。 首先&#xff0c;國企和外企不能一概而論。正如任何事物都有三六九等&#xff0c;這個&#xff0c;只能在同等級別上進行比較。 國企分類&#xff1a; 一等國企&#xff1…

Python | 使用matplotlib.pyplot創建線圖

Problem statement: Write a program in python (using matplotlib.pyplot) to create a line plot. 問題陳述&#xff1a;用python編寫程序(使用matplotlib.pyplot)以創建線圖。 Program: 程序&#xff1a; import matplotlib.pyplot as pltx [1,2,3,4,5,6,7,8,9,10]y [3,…

QI(接口查詢)

接觸AE一段時間了&#xff0c;總的來說收獲不少&#xff0c;今天仔細分析了一下AE開發中經常會用到的QI即接口查詢&#xff0c;有了自己的一些理解。 COM類至少有一個接口。事實上一般它們有好幾個接口。即一個類經常會實現多個接口&#xff08;一個類無法繼承多個類&#xff0…

linux內核設計與實現---從內核出發

獲取、編譯、安裝內核1 獲取內核源碼安裝內核源代碼何處安裝源碼使用補丁2 內核源碼樹3 編譯內核減少編譯的垃圾信息衍生多個編譯作業安裝內核啟用指定內核作為引導4 內核開發的特點沒有libc庫頭文件沒有內存保護機制容積小而固定的棧1 獲取內核源碼 在linux內核官方網站http:…

MySQL在DOS下的基本命令操作

啟動net start mysql 重置root密碼 方法一:在my.ini的[mysqld]字段加入&#xff1a; skip-grant-tables 重啟mysql服務&#xff0c;這時的mysql不需要密碼即可登錄數據庫然后進入mysql mysql>use mysql;mysql>更新 user set passwordpassword(新密碼) WHERE Userroot; …