FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_2示例
heap_2.c
內(nèi)存堆管理
heap_2和heap_1一樣是開辟一個(gè)大數(shù)組作為堆空間供用戶使用,但是采用單項(xiàng)不循環(huán)鏈表來管理內(nèi)存的分配釋放,主要思想是用鏈表把內(nèi)存塊串起來,數(shù)據(jù)結(jié)構(gòu)如下
/* Define the linked list structure. This is used to link free blocks in order of their size. */ typedef struct A_BLOCK_LINK { //指向下一個(gè)空閑內(nèi)存塊管理結(jié)構(gòu)體 struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ //記錄申請(qǐng)的字節(jié)數(shù),包括鏈表占用所占字節(jié)數(shù) size_t xBlockSize; /*<< The size of the free block. */ } BlockLink_t;
與引入鏈表管理而帶來的相關(guān)變量如下
//鏈表結(jié)構(gòu)體對(duì)齊后所占字節(jié)數(shù) static const uint16_t heapSTRUCT_SIZE = ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); //2倍鏈表結(jié)構(gòu)體對(duì)齊后所占字節(jié)數(shù),這作為一個(gè)閾值,在分配時(shí)起作用 #define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) ) /* Create a couple of list links to mark the start and end of the list. */ //定義2個(gè)局部靜態(tài)全局結(jié)構(gòu)體變量用于管理 static BlockLink_t xStart, xEnd;
還剩空閑字節(jié)數(shù)
/* Keeps track of the number of free bytes remaining, but says nothing about fragmentation. */ static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;
分配
void *pvPortMalloc( size_t xWantedSize ) { BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; static BaseType_t xHeapHasBeenInitialised = pdFALSE; void *pvReturn = NULL; //掛起調(diào)度器,防止函數(shù)重入 vTaskSuspendAll(); { /* If this is the first call to malloc then the heap will require initialisation to setup the list of free blocks. */ //第一次調(diào)用會(huì)初始化內(nèi)存堆 if( xHeapHasBeenInitialised == pdFALSE ) { prvHeapInit(); xHeapHasBeenInitialised = pdTRUE; } /* The wanted size is increased so it can contain a BlockLink_t structure in addition to the requested amount of bytes. */ if( xWantedSize > 0 ) { //用戶分配字節(jié)數(shù)+管理結(jié)構(gòu)體占用字節(jié)數(shù) xWantedSize += heapSTRUCT_SIZE; /* Ensure that blocks are always aligned to the required number of bytes. */ //總的字節(jié)數(shù)再做此字節(jié)對(duì)齊 if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0 ) { /* Byte alignment required. */ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); } } //待分配字節(jié)數(shù)大于0且小于總共堆字節(jié)數(shù) if( ( xWantedSize > 0 ) && ( xWantedSize < configADJUSTED_HEAP_SIZE ) ) { /* Blocks are stored in byte order - traverse the list from the start (smallest) block until one of adequate size is found. */ //pxPreviousBlock指向頭鏈表 pxPreviousBlock = &xStart; //pxBlock指向第一個(gè)開始空閑塊 pxBlock = xStart.pxNextFreeBlock; //當(dāng)pxBlock所管理的空閑塊字節(jié)數(shù)小于待分配的 //且沒有遍歷到空閑塊管理鏈表尾部則一直遍歷 while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) { //pxPreviousBlock這里是保存當(dāng)前空閑塊管理結(jié)構(gòu)體,為了后面找到返回的內(nèi)存地址 pxPreviousBlock = pxBlock; //指向下一個(gè)空閑塊管理結(jié)構(gòu)體 pxBlock = pxBlock->pxNextFreeBlock; } /* If we found the end marker then a block of adequate size was not found. */ //pxBlock不等于結(jié)尾說明找到符合大小的空閑塊 if( pxBlock != &xEnd ) { /* Return the memory space - jumping over the BlockLink_t structure at its start. */ //pvReturn用作返回給用戶,這里要偏移一個(gè)空閑塊管理結(jié)構(gòu)體占用內(nèi)存大小 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. */ //因?yàn)閜xPreviousBlock->pxNextFreeBlock指向的空閑塊被分配了, //所以要把pxPreviousBlock->pxNextFreeBlock指向的空閑塊移除出去, //也就是pxPreviousBlock->pxNextFreeBlock指向pxBlock->pxNextFreeBlock //也就是跳過分配出去的那個(gè)塊 pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; /* If the block is larger than required it can be split into two. */ //這里判斷, //如果將要分配出去的內(nèi)存塊大小xBlockSize比分配出去的還要大heapMINIMUM_BLOCK_SIZE(2倍管理結(jié)構(gòu)體) //為了節(jié)約就把再分成2塊,一塊返回給用戶, //一塊構(gòu)造一個(gè)新的空閑管理結(jié)構(gòu)體后插入空閑鏈表 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. */ //注意這里xWantedSize是管理結(jié)構(gòu)體和和真正需要字節(jié)數(shù)之和 //所以是在pxBlock基礎(chǔ)上偏移xWantedSize作為新的管理結(jié)構(gòu)體 pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); /* Calculate the sizes of two blocks split from the single block. */ //pxNewBlockLink新的管理結(jié)構(gòu)體大小 //是待分配pxBlock->xBlockSize-xWantedSize pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; //更新pxBlock->xBlockSize大小為xWantedSize pxBlock->xBlockSize = xWantedSize; /* Insert the new block into the list of free blocks. */ //把新構(gòu)造的空閑管理結(jié)構(gòu)體按xBlockSize大小升序插入到空閑鏈表 prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); } //還剩空閑字節(jié)數(shù)要減去分配出去的 xFreeBytesRemaining -= pxBlock->xBlockSize; } } traceMALLOC( pvReturn, xWantedSize ); }//解掛調(diào)度器 ( void ) xTaskResumeAll(); //如果定義了申請(qǐng)失敗鉤子函數(shù),這里將執(zhí)行 #if( configUSE_MALLOC_FAILED_HOOK == 1 ) { if( pvReturn == NULL ) { extern void vApplicationMallocFailedHook( void ); vApplicationMallocFailedHook(); } } #endif //返回給用戶 return pvReturn; }
其中xFreeBytesRemaining
初始化如下
/* Keeps track of the number of free bytes remaining, but says nothing about fragmentation. */ static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;
初始化內(nèi)存堆
static void prvHeapInit( void ) { BlockLink_t *pxFirstFreeBlock; uint8_t *pucAlignedHeap; /* Ensure the heap starts on a correctly aligned boundary. */ //與heap1操作相同,確保portBYTE_ALIGNMENT字節(jié)對(duì)齊,實(shí)際使用的首址是pucAlignedHeap pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( 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. */ //空閑鏈表結(jié)構(gòu)體頭部初始化,pxNextFreeBlock指向?qū)嶋H使用的首址pucAlignedHeap xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap; //空閑鏈表結(jié)構(gòu)體頭部沒有可用內(nèi)存,所以xBlockSize是0 xStart.xBlockSize = ( size_t ) 0; /* xEnd is used to mark the end of the list of free blocks. */ //空閑鏈表結(jié)構(gòu)體尾部初始化,xBlockSize=configADJUSTED_HEAP_SIZE僅僅是為了后面的升序排列,不代表可以空閑字節(jié)數(shù) xEnd.xBlockSize = configADJUSTED_HEAP_SIZE; //空閑鏈表結(jié)構(gòu)體尾部初始化,pxNextFreeBlock指向NULL表示結(jié)尾 xEnd.pxNextFreeBlock = NULL; /* To start with there is a single free block that is sized to take up the entire heap space. */ //第一個(gè)空閑塊,pxFirstFreeBlock,即上面xStart指向的pucAlignedHeap pxFirstFreeBlock = ( void * ) pucAlignedHeap; //可以空閑內(nèi)存為configADJUSTED_HEAP_SIZE pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE; //指向空閑鏈表結(jié)構(gòu)體尾部 pxFirstFreeBlock->pxNextFreeBlock = &xEnd; }
初始化后的示意圖如下
這里注意xBlockSize是包括管理結(jié)構(gòu)體占用內(nèi)存大小的(出來xStart和xEnd之外,這2個(gè)做排序用)
把新構(gòu)造的結(jié)構(gòu)體插入空閑鏈表
/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */ /* * Insert a block into the list of free blocks - which is ordered by size of * the block. Small blocks at the start of the list and large blocks at the end * of the list. */ #define prvInsertBlockIntoFreeList( pxBlockToInsert ) \ { \ BlockLink_t *pxIterator; \ size_t xBlockSize; \ \ //這里獲得新構(gòu)造的空閑結(jié)構(gòu)體成員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; \ }
釋放
釋放就很簡單了,就是偏移下地址后直接插入空閑鏈表
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; //掛起調(diào)度器 vTaskSuspendAll(); { /* Add this block to the list of free blocks. */ //插入空閑鏈表 prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); //剩余空閑內(nèi)存增加 xFreeBytesRemaining += pxLink->xBlockSize; traceFREE( pv, pxLink->xBlockSize ); }//解掛調(diào)度器 ( void ) xTaskResumeAll(); } }
還??臻e字節(jié)數(shù)
size_t xPortGetFreeHeapSize( void ) { return xFreeBytesRemaining; }
適用范圍、特點(diǎn)
適用于需要釋放的場合,且每次申請(qǐng)釋放的內(nèi)存都是固定大小的,因?yàn)獒尫艜r(shí)不會(huì)合并相鄰空閑內(nèi)存塊,所以如果每次申請(qǐng)釋放都是隨機(jī)的,到最后即使剩余內(nèi)存大于要想要分配,由于有很多小的內(nèi)存碎片導(dǎo)致最終分配失敗。
以上就是FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_2示例的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS動(dòng)態(tài)內(nèi)存管理heap_2的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)概要講解
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)概要講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)特點(diǎn)介紹
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)特點(diǎn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS使用任務(wù)通知實(shí)現(xiàn)命令行解釋器
這篇文章主要為大家介紹了FreeRTOS使用任務(wù)通知實(shí)現(xiàn)命令行解釋器,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS編碼標(biāo)準(zhǔn)及風(fēng)格指南
這篇文章主要為大家介紹了FreeRTOS編碼標(biāo)準(zhǔn)及風(fēng)格指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS信號(hào)量API函數(shù)基礎(chǔ)教程
這篇文章主要為大家介紹了FreeRTOS信號(hào)量API函數(shù)的基礎(chǔ)教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)在Cortex-M3上的移植過程
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)在Cortex-M3上的移植過程的示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之任務(wù)通知示例完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階系列之任務(wù)通知的示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS任務(wù)控制API函數(shù)的功能分析
這篇文章主要為大家介紹了FreeRTOS任務(wù)控制API函數(shù)的功能分析,F(xiàn)reeRTOS任務(wù)控制API函數(shù)主要實(shí)現(xiàn)任務(wù)延時(shí)、任務(wù)掛起、解除任務(wù)掛起、任務(wù)優(yōu)先級(jí)獲取和設(shè)置等功能2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)通知方法
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)通知方法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04