FreeRTOS---内存管理笔记

参考:https://blog.csdn.net/zhzht19861011/article/details/51606068

FreeRTOS分为5种内存管理方式,在这里记录对于内存管理方式的理解。

 

一、heap_1

1、heap_1,只允许管理一个静态的数组ucHeap,内存从静态Ram中由系统分配,不能指定管理外部SRAM,或者管理堆中的内存

2、直接按照申请的内存的大小,从空闲内存中划分内存

3、分配的内存无法回收

      这种内存分配方式最简单直接,速度快程序简单。适用于分配完内存后不需要回收的场合。

#include <stdlib.h>

/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers.  That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE

#include "FreeRTOS.h"
#include "task.h"

#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE

//heap_1.h的内存管理方式,只允许管理一个静态的数组ucHeap,内存从静态Ram中由系统分配
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
	#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif


//首地址按portBYTE_ALIGNMENT对齐后内存容量的大小
#define configADJUSTED_HEAP_SIZE	( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )

#if( configAPPLICATION_ALLOCATED_HEAP == 1 )

	extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
	//heap_1内存分配,直接由Ram中划分一个数组,进行内存管理。
	static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif 

//当前占用内存数
static size_t xNextFreeByte = ( size_t ) 0;

/*-----------------------------------------------------------*/

void *pvPortMalloc( size_t xWantedSize )
{
//此指针指向分配的地址
void *pvReturn = NULL;
//按portBYTE_ALIGNMENT对齐后内存首地址
static uint8_t *pucAlignedHeap = NULL;

	//对齐方式不为1的,申请内存数需要按照portBYTE_ALIGNMENT对齐
	#if( portBYTE_ALIGNMENT != 1 )
	{
		//相当于xWantedSize%portBYTE_ALIGNMENT
		if( xWantedSize & portBYTE_ALIGNMENT_MASK )
		{
			//将xWantedSize按照portBYTE_ALIGNMENT强制对齐
			xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
		}
	}
	#endif
    
	//挂起任务防止重入
	vTaskSuspendAll();
	{
		//pucAlignedHeap存储按portBYTE_ALIGNMENT对齐后的有效内存首地址
		if( pucAlignedHeap == NULL )
		{
			pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
		}

		//边界检查,检查当前剩余内存容量是否足够分配,且检查xWantedSize是否为正数
		if( ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) &&
			( ( xNextFreeByte + xWantedSize ) > xNextFreeByte )	)
		{
			//将剩余内存的首地址返回给用户
			pvReturn = pucAlignedHeap + xNextFreeByte;
			//当前占用内存数增加
			xNextFreeByte += xWantedSize;
		}
        //用于输出内存分配信息的宏,默认为空不起作用
		traceMALLOC( pvReturn, xWantedSize );
	}
	//恢复任务
	( void ) xTaskResumeAll();

	#if( configUSE_MALLOC_FAILED_HOOK == 1 )
	{
		//如果分配内存失败,调用回调函数
		if( pvReturn == NULL )
		{
			extern void vApplicationMallocFailedHook( void );
			vApplicationMallocFailedHook();
		}
	}
	#endif

	return pvReturn;
}
/*-----------------------------------------------------------*/

void vPortFree( void *pv )
{
	//什么都不做,因为heap_1分配的内存不需要回收
	( void ) pv;

	configASSERT( pv == NULL );
}
/*-----------------------------------------------------------*/

void vPortInitialiseBlocks( void )
{
	//将表示已占用内存数的局部变量清零
	//如果清零后再次调用pvPortMalloc();将会出错
	//可能导致两个已分配指针使用同一块内存
	xNextFreeByte = ( size_t ) 0;
}
/*-----------------------------------------------------------*/

size_t xPortGetFreeHeapSize( void )
{
	//用于获取当前剩余可用内存大小
	return ( configADJUSTED_HEAP_SIZE - xNextFreeByte );
}

二、heap_2

1、使用链表管理,链表数据域为:有效内存数量 + 结点占用空间

2、链表的头结点、尾结点不存于管理的内存中,其他结点存于管理的内存中。头结点指向内存中首个结点,首结点

      指向尾结点。尾结点指针域为Null。首结点数据域为地址对齐后所有有效内存数。

3、内存的申请:

     (1) 从链表中找到一个节点,它的数据域大于需要申请的内存数 + 结点占用内存数(不能为尾结点)

     (2) 将这个节点从链表中删除,代表它已经分配给用户

     (3) 这个节点首地址减去结点本身占用内存之后的地址,将会返回给用户使用

     (4) 判断剩余的内存,是否足够再组成一个新的结点

     (5) 如果能组成一个结点,则将新结点按照从小到大排列顺序插入到链表,不能则返回

4、内存的释放:

     (1) 将用户指针 - 结点占用内存的大小,得到的就是管理此块内存的结点的首地址。

     (2) 将此结点插入到链表中

       这种分配方式通过链表进行管理,支持内存的释放,支持管理外部SRAM。如果申请跟释放内存的大小是固定的,如32byte。频繁的申请与释放并不会造成碎片,且申请与释放速度快。但如果申请内存不固定,频繁申请与释放将会造成内存碎片。

#include <stdlib.h>

/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers.  That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE

#include "FreeRTOS.h"
#include "task.h"

#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE

#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
	#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif

//首地址按portBYTE_ALIGNMENT对齐后内存容量大小
#define configADJUSTED_HEAP_SIZE	( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )


static void prvHeapInit( void );

//heap_2允许管理指定地址的内存
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
	extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
	static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif 


//链表结构体定义
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;


//将链表结构体的大小按照portBYTE_ALIGNMENT进行对齐
static const uint16_t heapSTRUCT_SIZE	= ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
//一个链表结点,占用内存最小为2倍的结点大小
#define heapMINIMUM_BLOCK_SIZE	( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )

//创建链表表头跟表尾
static BlockLink_t xStart, xEnd;

//此变量记录空闲内存容量
static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;


//此宏定义,将一个节点插入链表
//顺序为内存从小到大排列,防止在遍历结点时,用户申请小容量内存却占用大容量内存的结点
#define prvInsertBlockIntoFreeList( pxBlockToInsert )								\
{																					\
BlockLink_t *pxIterator;															\
size_t xBlockSize;																	\
																						\
	xBlockSize = pxBlockToInsert->xBlockSize;										\
																					\
																					\
	//遍历链表,找到一个节点pxIterator,它指向的结点的xBlockSize大于或等于需要插入的结点
	for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock )	\
	{																				\
		/* There is nothing to do here - just iterate to the correct position. */	\
	}																				\
																					\

	//将需要插入的结点pxBlockToInsert,插入到pxIterator的后面																			
	pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;					\
	pxIterator->pxNextFreeBlock = pxBlockToInsert;									\
}
/*-----------------------------------------------------------*/

void *pvPortMalloc( size_t xWantedSize )
{
//定义三个结点,pxBlock为xBlockSize大于等于申请内存数的结点
//pxPreviousBlock为pxBlock上一结点,pxNewBlockLink为从pxBlock分割的新建结点
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
//定义一个静态变量xHeapHasBeenInitialised,初始值为0,用作初始化heap的标志位
static BaseType_t xHeapHasBeenInitialised = pdFALSE;
void *pvReturn = NULL;

	vTaskSuspendAll();
	{
        //判断是否需要初始化heap
		if( xHeapHasBeenInitialised == pdFALSE )
		{
			prvHeapInit();
			xHeapHasBeenInitialised = pdTRUE;
		}

		
		if( xWantedSize > 0 )
		{
			//申请的内存,加上结点结构体占用的内存,即为所需的总内存大小(xWantedSize)
			xWantedSize += heapSTRUCT_SIZE;

			//申请内存数,按照portBYTE_ALIGNMENT_MASK对齐
			if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0 )
			{
				xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
			}
		}


		if( ( xWantedSize > 0 ) && ( xWantedSize < configADJUSTED_HEAP_SIZE ) )
		{
			//头结点开始遍历链表,找到内存大于或等于xWantedSize的结点pxBlock
			//pxPreviousBlock为pxBlock前结点
			pxPreviousBlock = &xStart;
			pxBlock = xStart.pxNextFreeBlock;
			while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
			{
				pxPreviousBlock = pxBlock;
				pxBlock = pxBlock->pxNextFreeBlock;
			}

			//pxBlock不能为尾结点
			if( pxBlock != &xEnd )
			{
				//pxBlock首地址 + 结点结构体大小,即为有效内存首地址
				pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );

				//pxPreviousBlock的指针域指向pxBlock的下一结点
				//相当于将pxBlock结点从链表中删除,因为结点pxBlock已经分配给用户了
				pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

				//判断结点剩余内存是否大于heapMINIMUM_BLOCK_SIZE,大于则新建结点
				if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
				{
					//新建结点,首地址为pxBlock剩余内存的首地址
					pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );

					//在剩余内存首地址创建一个节点,BlockSize为剩余内存
					pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
					//pxBlock的xBlockSize大小改为xWantedSize
					pxBlock->xBlockSize = xWantedSize;

					//新的结点插入到链表中
					prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
				}
                //空闲内存记录变量更新
				xFreeBytesRemaining -= pxBlock->xBlockSize;
			}
		}

		traceMALLOC( pvReturn, xWantedSize );
	}
	( void ) xTaskResumeAll();

	#if( configUSE_MALLOC_FAILED_HOOK == 1 )
	{
		if( pvReturn == NULL )
		{
			extern void vApplicationMallocFailedHook( void );
			vApplicationMallocFailedHook();
		}
	}
	#endif

	return pvReturn;
}
/*-----------------------------------------------------------*/

void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;

	if( pv != NULL )
	{
		//获取此内存块的结点的首地址
		puc -= heapSTRUCT_SIZE;

		//将结点首地址赋值给pxLink
		pxLink = ( void * ) puc;

		vTaskSuspendAll();
		{
			//将此结点插入到空闲链表中
			prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
			//更新剩余内存数
			xFreeBytesRemaining += pxLink->xBlockSize;
			traceFREE( pv, pxLink->xBlockSize );
		}
		( void ) xTaskResumeAll();
	}
}
/*-----------------------------------------------------------*/

size_t xPortGetFreeHeapSize( void )
{
	return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/

void vPortInitialiseBlocks( void )
{
	/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/

//heap初始化函数,初始化头结点与尾结点
//且在有效内存首地址创建一个节点,头结点指向它,它指向尾结点,xBlockSize为对齐后有效内存总数
static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;

	//pucAlignedHeap为内存按portBYTE_ALIGNMENT对齐后的有效内存首地址
	pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );

	//链表头结点指向有效内存的首地址
	xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
	xStart.xBlockSize = ( size_t ) 0;

	//链表尾结点指针域为空,数据域为有效内存数
	xEnd.xBlockSize = configADJUSTED_HEAP_SIZE;
	xEnd.pxNextFreeBlock = NULL;

	//在对齐地址后的有效内存首地址,创建一个结点
	//结点指针域指向尾结点,数据域为对齐地址后有效内存容量
	pxFirstFreeBlock = ( void * ) pucAlignedHeap;
	pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE;
	pxFirstFreeBlock->pxNextFreeBlock = &xEnd;
}
/*-----------------------------------------------------------*/

三、heap_3

1、此管理方式封装标准库中的内存管理函数,管理的是启动文件中设置的heap。

      封装过程中添加的是挂起、恢复调度器的函数,用来保护线程。

      此外,它并不能显示我们剩余的空闲内存的大小

 

四、heap_4

1、跟heap_2一样采用链表进行管理

2、增加了内存块的合并算法,满足条件下先合并前结点再合并后结点,消除内存碎片

3、结点数据域最高位作为标志位,用于检查内存块的状态,为1代表被占用,0则空闲

4、链表中结点按地址从小到大排序,与heap_2的按内存从小到大排列不同

5、因为遍历结点的条件是地址大小。不同于heap_2按照内存大小,所以尾结点放置于内存中,用于结束遍历

#include <stdlib.h>

/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers.  That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE

#include "FreeRTOS.h"
#include "task.h"

#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE

#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
	#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif

#define heapMINIMUM_BLOCK_SIZE	( ( size_t ) ( xHeapStructSize << 1 ) )


#define heapBITS_PER_BYTE		( ( size_t ) 8 )


#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
	
	extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
	static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif 


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;

/*-----------------------------------------------------------*/


static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );


static void prvHeapInit( void );

/*-----------------------------------------------------------*/

//结点大小,按portBYTE_ALIGNMENT对齐
static const size_t xHeapStructSize	= ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );

//头结点位于Ram中,尾结点位于管理的内存中
static BlockLink_t xStart, *pxEnd = NULL;

//记录可用内存数
static size_t xFreeBytesRemaining = 0U;
//记录剩余内存历史最小值
static size_t xMinimumEverFreeBytesRemaining = 0U;
//用于判断以及改变结点数据域最高位
static size_t xBlockAllocatedBit = 0;

/*-----------------------------------------------------------*/

void *pvPortMalloc( size_t xWantedSize )
{
//pxBlock为分配内存给用户的结点,pxPreviousBlock为pxBlock的前结点,pxNewBlockLink为新建结点
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
//此指针返回分配的内存给用户
void *pvReturn = NULL;

	vTaskSuspendAll();
	{
		//初始化heap
		if( pxEnd == NULL )
		{
			prvHeapInit();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		//申请内存数不能影响到标志位
		if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
		{
			
			if( xWantedSize > 0 )
			{
				xWantedSize += xHeapStructSize;

				//申请内存数按portBYTE_ALIGNMENT对齐
				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 ) )
			{
				//找到剩余内存大于申请内存的结点pxBlock
				pxPreviousBlock = &xStart;
				pxBlock = xStart.pxNextFreeBlock;
				while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
				{
					pxPreviousBlock = pxBlock;
					pxBlock = pxBlock->pxNextFreeBlock;
				}

				
				if( pxBlock != pxEnd )
				{
					//返回pxBlock中内存的首地址
					pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );

					//pxBlock的前结点改为指向pxBlock的后结点,pxBlock从链表中删除
					pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

					//如果pxBlock剩余内存足够创建一个新的节点
					if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
					{
						//新节点首地址为用户申请的内存后的首地址
						pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
						
						//一个宏定义,如果新建的结点首地址不按照portBYTE_ALIGNMENT对齐,进入死循环
						//#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );} 
						configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );

						//计算新建结点拥有的内存
						pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
						//更新pxBlock的内存块大小
						pxBlock->xBlockSize = xWantedSize;

						//将新建的结点按照地址从小到大插入到链表
						prvInsertBlockIntoFreeList( pxNewBlockLink );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					//更新剩余内存大小
					xFreeBytesRemaining -= pxBlock->xBlockSize;

					//更新最小剩余内存的记录
					if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
					{
						xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					//pxBlock的数据域最高位置1,代表此内存块被占用
					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( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
	return pvReturn;
}
/*-----------------------------------------------------------*/

void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;

	if( pv != NULL )
	{
		//指针地址减去链表结构体的大小,为指针所在结点的首地址
		puc -= xHeapStructSize;

		//pxLink为结点首地址
		pxLink = ( void * ) puc;

		configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
		configASSERT( pxLink->pxNextFreeBlock == NULL );

		//如果结点数据域标志位为1,代表此结点内存被占用,进行释放操作
		if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
		{
			//检查是否为可释放的结点
			if( pxLink->pxNextFreeBlock == NULL )
			{
				//将数据域最高位置0,表示此结点为空闲态
				pxLink->xBlockSize &= ~xBlockAllocatedBit;

				vTaskSuspendAll();
				{
					//剩余内存数更新
					xFreeBytesRemaining += pxLink->xBlockSize;
					traceFREE( pv, pxLink->xBlockSize );
					//将此结点插入到链表
					prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
				}
				( void ) xTaskResumeAll();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
}
/*-----------------------------------------------------------*/

size_t xPortGetFreeHeapSize( void )
{
	return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/

size_t xPortGetMinimumEverFreeHeapSize( void )
{
	return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/

void vPortInitialiseBlocks( void )
{
	/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/

static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;

	
	uxAddress = ( size_t ) ucHeap;

	//首地址按照portBYTE_ALIGNMENT对齐
	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.pxNextFreeBlock = ( void * ) pucAlignedHeap;
	xStart.xBlockSize = ( size_t ) 0;

	//内存尾部预留创建一个节点的内存
	//因为链表按照地址遍历,所以尾结点放置于内存中
	uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
	uxAddress -= xHeapStructSize;
	//地址上移,按照portBYTE_ALIGNMENT对齐
	uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
	pxEnd = (void *) uxAddress;
	pxEnd->xBlockSize = 0;
	pxEnd->pxNextFreeBlock = NULL;

	//内存首地址创建结点,它的有效内存为内存起始地址到尾结点首地址
	pxFirstFreeBlock = ( void * ) pucAlignedHeap;
	pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
	pxFirstFreeBlock->pxNextFreeBlock = pxEnd;

	xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
	xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;

	//标志位为size_t数据类型的最高位置1
	xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}
/*-----------------------------------------------------------*/

static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
{
//定义一个结点指针
BlockLink_t *pxIterator;
uint8_t *puc;

	//遍历链表,找到一个结点pxIterator,它指向的结点的地址大于pxBlockToInsert,称为前结点
	for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
	{
		/* Nothing to do here, just iterate to the right position. */
	}

	/************************ 结点的合并 **************************/
	
	//如果前结点,跟pxBlockToInsert连续,pxBlockToInsert将被前结点合并
	puc = ( uint8_t * ) pxIterator;
	if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
	{
		//被前结点合并,前结点的指针域不需要更新
		//前结点数据域增加
		pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
		//pxBlockToInsert与前结点为同一结点
		pxBlockToInsert = pxIterator;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	//如果pxBlockToInsert跟找到的结点指向的下一结点(后结点)连续,则pxBlockToInsert合并后结点
	puc = ( uint8_t * ) pxBlockToInsert;
	if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
	{
		if( pxIterator->pxNextFreeBlock != pxEnd )
		{
			//pxBlockToInsert数据域增加
			pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
			//pxBlockToInsert合并后结点,被插入结点需要更新指针域
			pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
		}
		else
		{
			//如果跟尾结点连续,则指针域改成指向尾结点
			pxBlockToInsert->pxNextFreeBlock = pxEnd;
		}
	}
	
	/************************ 结点的插入 **************************/
	else
	{
		//如果不连续,pxBlockToInsert指向后结点
		pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
	}

	//前结点跟pxBlockToInsert不同,代表前结点跟pxBlockToInsert不连续
	if( pxIterator != pxBlockToInsert )
	{
		//前结点指向pxBlockToInsert
		pxIterator->pxNextFreeBlock = pxBlockToInsert;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

 

五、heap_5

1、内存的申请、释放,结点的插入,与heap_4一致。

2、内存的初始化不同,heap_5可以初始化多个地址不连续的内存块,一同管理。

      前一内存块尾结点指向后一内存块头结点,最后一个内存块尾结点为Null

3、初始化之前,需要用户自定义内存块地址以及大小

4、初始化函数不能重复运行,以及未初始化之前不能申请内存,否则都会进入死循环

#include <stdlib.h>

#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE

#include "FreeRTOS.h"
#include "task.h"

#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE

#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
	#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif

#define heapMINIMUM_BLOCK_SIZE	( ( size_t ) ( xHeapStructSize << 1 ) )

#define heapBITS_PER_BYTE		( ( size_t ) 8 )


///* Used by heap_5.c. */
//typedef struct HeapRegion
//{
//	uint8_t *pucStartAddress;  //指向一个地址
//	size_t xSizeInBytes;       //此内存块的大小
//} HeapRegion_t;


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;

/*-----------------------------------------------------------*/

static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );

/*-----------------------------------------------------------*/
//链表结构体大小按照portBYTE_ALIGNMENT对齐
static const size_t xHeapStructSize	= ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );

//定义头结点、尾结点指针,尾结点位于内存中
static BlockLink_t xStart, *pxEnd = NULL;

//记录剩余内存
static size_t xFreeBytesRemaining = 0U;
//记录历史最小剩余内存
static size_t xMinimumEverFreeBytesRemaining = 0U;

//结点内存状态位标志
static size_t xBlockAllocatedBit = 0;

/*-----------------------------------------------------------*/

void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;

	//pxEnd为空证明未执行初始化,进入死循环
	configASSERT( pxEnd );

	vTaskSuspendAll();
	{
		//申请内存数不能大于2GB,影响内存状态标志位
		if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
		{
			
			//申请内存数加上结点占用内存后,按照portBYTE_ALIGNMENT对齐
			if( xWantedSize > 0 )
			{
				xWantedSize += xHeapStructSize;
			
				if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
				{
					xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}


			if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
			{
				//遍历结点,找到内存数大于等于申请内存数的结点pxBlock,将其分配给用户
				pxPreviousBlock = &xStart;
				pxBlock = xStart.pxNextFreeBlock;
				while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
				{
					pxPreviousBlock = pxBlock;
					pxBlock = pxBlock->pxNextFreeBlock;
				}
			
				if( pxBlock != pxEnd )
				{
					//pxBlock中的内存首地址返回给用户
					pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );

					//pxBlock的前结点改为指向pxBlock的后结点,pxBlock从链表中删除
					pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

					//如果pxBlock中剩余内存大于新建一个节点所需内存
					if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
					{
						//新建一个节点,位于pxBlock剩余内存的首地址
						pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );

						//计算新建结点的内存数
						pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
						//更新pxBlock的内存数
						pxBlock->xBlockSize = xWantedSize;

						//将新建的结点插入到链表,顺序为按照地址从小到大
						prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					//更新剩余内存数
					xFreeBytesRemaining -= pxBlock->xBlockSize;

					//更新最小剩余内存历史
					if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
					{
						xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					//pxBlock数据域最高位置1,标志此结点内存被占用
					pxBlock->xBlockSize |= xBlockAllocatedBit;
					//被分配的结点,指针域设为Null
					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

	return pvReturn;
}
/*-----------------------------------------------------------*/

void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;

	if( pv != NULL )
	{
		//计算指针所处结点的首地址
		puc -= xHeapStructSize;

        //pxLink存放指针所处结点首地址
		pxLink = ( void * ) puc;

		//抛出异常
		configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
		configASSERT( pxLink->pxNextFreeBlock == NULL );

		//如果结点的数据域标志位为1,进行释放操作
		if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
		{
			//如果结点的指针域为空
			if( pxLink->pxNextFreeBlock == NULL )
			{
				//数据域标志位更新为0
				pxLink->xBlockSize &= ~xBlockAllocatedBit;

				vTaskSuspendAll();
				{
					//更新空闲内存数
					xFreeBytesRemaining += pxLink->xBlockSize;
					traceFREE( pv, pxLink->xBlockSize );
					//将结点插入到链表,顺序为按地址从小到大
					prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
				}
				( void ) xTaskResumeAll();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
}
/*-----------------------------------------------------------*/

size_t xPortGetFreeHeapSize( void )
{
	return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/

size_t xPortGetMinimumEverFreeHeapSize( void )
{
	return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/

static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
{
BlockLink_t *pxIterator;
uint8_t *puc;

	//遍历链表,找到一个节点pxIterator,它指向的结点的地址大于pxBlockToInsert,称为前结点
	for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
	{
		/* Nothing to do here, just iterate to the right position. */
	}

	//如果pxBlockToInsert,与前结点连续,则合并两个结点,合并后结点首地址为前结点首地址
	puc = ( uint8_t * ) pxIterator;
	if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
	{
		//更新合并后的结点的数据域
		pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
		//pxBlockToInsert的指针域,指向合并后结点的首地址
		pxBlockToInsert = pxIterator;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	//如果pxBlockToInsert,与前结点指向的结点(后结点)连续,则合并两个结点,合并后结点首地址为pxBlockToInsert的首地址
	puc = ( uint8_t * ) pxBlockToInsert;
	if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
	{
		if( pxIterator->pxNextFreeBlock != pxEnd )
		{
			//更新pxBlockToInsert的数据域
			pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
			//更新pxBlockToInsert的指针域
			pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
		}
		else
		{
			//后结点为尾结点,pxBlockToInsert指向尾结点
			pxBlockToInsert->pxNextFreeBlock = pxEnd;
		}
	}
	else
	{
		//如果pxBlockToInsert与后结点不连续,pxBlockToInsert指向后结点
		pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
	}

	//如果前结点与pxBlockToInsert没有合并
	if( pxIterator != pxBlockToInsert )
	{
		//前结点指向pxBlockToInsert,pxBlockToInsert成功插入到链表中
		pxIterator->pxNextFreeBlock = pxBlockToInsert;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}
/*-----------------------------------------------------------*/
//传递的结构体指针不可修改,且指针指向的内存也不可修改
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )
{
//pxFirstFreeBlockInRegion缓存当前内存块的头结点地址,pxPreviousFreeBlock缓存上一个内存块尾结点地址
BlockLink_t *pxFirstFreeBlockInRegion = NULL, *pxPreviousFreeBlock;

//记录对齐地址后内存块首地址
size_t xAlignedHeap;

//xTotalRegionSize代表的是本内存块总的内存数,xTotalHeapSize代表所有内存块内存数
size_t xTotalRegionSize, xTotalHeapSize = 0;

//记录结构体数组中的元素,从元素0到元素n,逐个初始化
BaseType_t xDefinedRegions = 0;

size_t xAddress;

//记录结构体数组每个元素的首地址
const HeapRegion_t *pxHeapRegion;

    //尾结点不为Null进入死循环
	configASSERT( pxEnd == NULL );

	//取结构体数组第一个元素首地址
	pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );

	//初始化结构体数组,当数组最后一个元素的xSizeInBytes为0,代表所有内存块初始化完毕
	//xSizeInBytes不为0则持续初始化内存块
	while( pxHeapRegion->xSizeInBytes > 0 )
	{
		//记录单个内存块的内存大小
		xTotalRegionSize = pxHeapRegion->xSizeInBytes;

		//记录当前内存块的首地址
		xAddress = ( size_t ) pxHeapRegion->pucStartAddress;
		//地址按照portBYTE_ALIGNMENT对齐
		if( ( xAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
		{
			xAddress += ( portBYTE_ALIGNMENT - 1 );
			xAddress &= ~portBYTE_ALIGNMENT_MASK;

			//更新内存大小
			xTotalRegionSize -= xAddress - ( size_t ) pxHeapRegion->pucStartAddress;
		}

		//记录经过对齐后当前内存块的首地址
		xAlignedHeap = xAddress;

		//如果当前为结构体数组第0元素
		if( xDefinedRegions == 0 )
		{
			//头结点初始化,指向此内存块首地址
			xStart.pxNextFreeBlock = ( BlockLink_t * ) xAlignedHeap;
			xStart.xBlockSize = ( size_t ) 0;
		}
		else  //否则检查尾结点与结构体数组元素的地址是否异常
		{	
			configASSERT( pxEnd != NULL );
			configASSERT( xAddress > ( size_t ) pxEnd );
		}
	
	    //指向尾结点,当初始化第二块内存块
		//此指针指向的是上一内存块尾结点
		pxPreviousFreeBlock = pxEnd;

	    //在此内存块尾部创建一个结点
		xAddress = xAlignedHeap + xTotalRegionSize;
		xAddress -= xHeapStructSize;
		xAddress &= ~portBYTE_ALIGNMENT_MASK;
		//尾结点指针指向当前内存块尾部
		pxEnd = ( BlockLink_t * ) xAddress;
		pxEnd->xBlockSize = 0;
		pxEnd->pxNextFreeBlock = NULL;

		//指向当前内存块首地址创建一个结点,此结点称为当前内存块首结点
		pxFirstFreeBlockInRegion = ( BlockLink_t * ) xAlignedHeap;
		//将当前内存块的内存数装载进首结点数据域
		pxFirstFreeBlockInRegion->xBlockSize = xAddress - ( size_t ) pxFirstFreeBlockInRegion;
		//首结点指向当前内存块尾结点
		pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;

		//当初始化第一个内存块,下面语句不被执行
		if( pxPreviousFreeBlock != NULL )
		{
			//让前一内存块的尾结点指向后一内存块的首结点
			pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;
		}

		//初始化完毕一个内存块,更新总内存块的内存大小
		xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;

		xDefinedRegions++;
		//指向结构体数组中下一个元素,对下一内存块进行初始化
		pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
	}

	//更新剩余内存数,以及历史最小剩余内存数
	xMinimumEverFreeBytesRemaining = xTotalHeapSize;
	xFreeBytesRemaining = xTotalHeapSize;

	configASSERT( xTotalHeapSize );

	//根据size_t数据类型占用字节数更新结点内存状态位标志
	xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}

 

六、myMalloc

将heap_5修改了一下,可脱离FreeRTOS使用。方便进行内存管理

头文件

#ifndef __bsp_Malloc_H
#define __bsp_Malloc_H


#include <stdlib.h>
#include "stm32f1xx_hal.h"

//定义管理的内存块的起始地址与大小
#define  Ram1Addr      (0x68000000UL)
#define  Ram1Size      (960*1024)

//定义中断屏蔽优先级
#define  configMAX_INTERRUPT_PRIORITY     2


#ifndef TEST_MARKER
	#define TEST_MARKER()
#endif

#ifndef myFORCE_INLINE
	#define myFORCE_INLINE __forceinline
#endif

  



typedef struct myHeapRegion
{
	uint8_t *pucStartAddress;  //指向一个地址
	size_t xSizeInBytes;       //此内存块的大小
} myHeapRegion_t;

extern myHeapRegion_t xHeapRegions[];




void *myMalloc( size_t xWantedSize );

void myFree( void *pv );

size_t myGetFreeHeapSize( void );

size_t myGetMinimumEverFreeHeapSize( void );

void myDefineHeapRegions( const myHeapRegion_t * const pxHeapRegions );

#endif


源文件

#include "bsp_Malloc.h"


typedef long BaseType_t;

#define  configUSE_MALLOC_FAILED_HOOK    0

#define  heapMINIMUM_BLOCK_SIZE	( ( size_t ) ( xHeapStructSize << 1 ) )
#define  heapBITS_PER_BYTE		( ( size_t ) 8 )

#define  portBYTE_ALIGNMENT              8
#define  portBYTE_ALIGNMENT_MASK        (portBYTE_ALIGNMENT - 1)


#define  MallocInterruptMask( )        vPortSetBASEPRI( )
#define  MallocInterruptRelease( )     vPortRaiseBASEPRI( )
#define  mallocASSERT( x ) if ((x) == 0) { for( ;; );} 


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;



myHeapRegion_t xHeapRegions[] =
 {
  	{ ( uint8_t * ) Ram1Addr, Ram1Size }, 
  	{ NULL, 0 }                
 };



/*-----------------------------------------------------------*/

static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );

/*-----------------------------------------------------------*/
static const size_t xHeapStructSize	= ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );

static BlockLink_t xStart, *pxEnd = NULL;

static size_t xFreeBytesRemaining = 0U;

static size_t xMinimumEverFreeBytesRemaining = 0U;

static size_t xBlockAllocatedBit = 0;

/*-----------------------------------------------------------*/

// 开中断
// 向basepri中写入0就表示开中断
static myFORCE_INLINE void vPortSetBASEPRI( void )
{
    __asm
    {
        msr basepri, 0
    }
}
// 关中断
// 向basepri中写入configMAX_INTERRUPT_PRIORITY,
// 表明优先级低于configMAX_INTERRUPT_PRIORITY的中断都会被屏蔽
static myFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_INTERRUPT_PRIORITY;

    __asm
    {
        msr basepri, ulNewBASEPRI
        dsb
        isb
    }
}
 
 
void *myMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
	
	mallocASSERT( pxEnd );
	MallocInterruptMask();
	{

		if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
		{
			
			if( xWantedSize > 0 )
			{
				xWantedSize += xHeapStructSize;
			
				if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
				{
					xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
				}
				else
				{
					TEST_MARKER();
				}
			}
			else
			{
				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 != pxEnd )
				{
					pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
					
					pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

					if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
					{
						pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );


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

						pxBlock->xBlockSize = xWantedSize;

						prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
					}
					else
					{
						TEST_MARKER();
					}

					xFreeBytesRemaining -= pxBlock->xBlockSize;

					if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
					{
						xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
					}
					else
					{
						TEST_MARKER();
					}

					pxBlock->xBlockSize |= xBlockAllocatedBit;
					
					pxBlock->pxNextFreeBlock = NULL;
				}
				else
				{
					TEST_MARKER();
				}
			}
			else
			{
				TEST_MARKER();
			}
		}
		else
		{
			TEST_MARKER();
		}

	}
	 MallocInterruptRelease();

	#if( configUSE_MALLOC_FAILED_HOOK == 1 )
	{
		if( pvReturn == NULL )
		{
			extern void vApplicationMallocFailedHook( void );
			vApplicationMallocFailedHook();
		}
		else
		{
			TEST_MARKER();
		}
	}
	#endif

	return pvReturn;
}
/*-----------------------------------------------------------*/

void myFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;

	if( pv != NULL )
	{
		puc -= xHeapStructSize;

		pxLink = ( void * ) puc;

		mallocASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
		mallocASSERT( pxLink->pxNextFreeBlock == NULL );

		if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
		{
			if( pxLink->pxNextFreeBlock == NULL )
			{
				pxLink->xBlockSize &= ~xBlockAllocatedBit;

				MallocInterruptMask();
				{
					xFreeBytesRemaining += pxLink->xBlockSize;
					prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
				}
				 MallocInterruptRelease();
			}
			else
			{
				TEST_MARKER();
			}
		}
		else
		{
			TEST_MARKER();
		}
	}
}
/*-----------------------------------------------------------*/

size_t myGetFreeHeapSize( void )
{
	return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/

size_t myGetMinimumEverFreeHeapSize( void )
{
	return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/

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. */
	}

	puc = ( uint8_t * ) pxIterator;
	if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
	{
		pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
		pxBlockToInsert = pxIterator;
	}
	else
	{
		TEST_MARKER();
	}

	puc = ( uint8_t * ) pxBlockToInsert;
	if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
	{
		if( pxIterator->pxNextFreeBlock != pxEnd )
		{
			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
	{
		TEST_MARKER();
	}
}
/*-----------------------------------------------------------*/
void myDefineHeapRegions( const myHeapRegion_t * const pxHeapRegions )
{
BlockLink_t *pxFirstFreeBlockInRegion = NULL, *pxPreviousFreeBlock;

size_t xAlignedHeap;

size_t xTotalRegionSize, xTotalHeapSize = 0;

BaseType_t xDefinedRegions = 0;

size_t xAddress;

const myHeapRegion_t *pxHeapRegion;

	mallocASSERT( pxEnd == NULL );

	pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );

	while( pxHeapRegion->xSizeInBytes > 0 )
	{
		xTotalRegionSize = pxHeapRegion->xSizeInBytes;

		xAddress = ( size_t ) pxHeapRegion->pucStartAddress;
		
		if( ( xAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
		{
			xAddress += ( portBYTE_ALIGNMENT - 1 );
			xAddress &= ~portBYTE_ALIGNMENT_MASK;

			xTotalRegionSize -= xAddress - ( size_t ) pxHeapRegion->pucStartAddress;
		}

		xAlignedHeap = xAddress;

		if( xDefinedRegions == 0 )
		{
			xStart.pxNextFreeBlock = ( BlockLink_t * ) xAlignedHeap;
			xStart.xBlockSize = ( size_t ) 0;
		}
		else 
		{	
			mallocASSERT( pxEnd != NULL );
			mallocASSERT( xAddress > ( size_t ) pxEnd );
		}
	
		pxPreviousFreeBlock = pxEnd;

		xAddress = xAlignedHeap + xTotalRegionSize;
		xAddress -= xHeapStructSize;
		xAddress &= ~portBYTE_ALIGNMENT_MASK;
		pxEnd = ( BlockLink_t * ) xAddress;
		pxEnd->xBlockSize = 0;
		pxEnd->pxNextFreeBlock = NULL;

		pxFirstFreeBlockInRegion = ( BlockLink_t * ) xAlignedHeap;
		pxFirstFreeBlockInRegion->xBlockSize = xAddress - ( size_t ) pxFirstFreeBlockInRegion;
		pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;

		if( pxPreviousFreeBlock != NULL )
		{
			pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;
		}

		xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;

		xDefinedRegions++;
		pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
	}

	xMinimumEverFreeBytesRemaining = xTotalHeapSize;
	xFreeBytesRemaining = xTotalHeapSize;

	mallocASSERT( xTotalHeapSize );

	xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}

 

程序在原子战舰V3通过测试:

 

观察断点,可知 j 比 k 大0x38,申请内存数为4、11、4,进行对齐后应该是8、16、8,加上3个结点占用的空间:24

共占用空间:56 = 0x38。  全部内存释放后,容量为0xEFFF8,刚好为:0xF0000 - 0x08。丢失的8字节被尾结点占用。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值