欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_2示例

 更新時(shí)間:2022年04月07日 15:11:58   作者:jiang_2018  
這篇文章主要介紹了FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_2示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪

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)文章

最新評(píng)論