FreeRTOS代码阅读笔记:heap_1.c

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZenNaiHeQiao/article/details/82757329

FreeRTOS中对于内存的管理当前一共有5种实现方式(作者当前的版本是10.1.1),均在【 \Source\portable\MemMang 】下面,这里笔记下。

重要的参数: 

使用方法:
头文件:FreeRTOSConfig.h 
配置参数:
configTOTAL_HEAP_SIZE             定义系统所用的堆栈大小。
configUSE_MALLOC_FAILED_HOOK      默认0: 1则开启钩子函数,内存分配失败则调用 

函数调用:	
      vPortInitialiseBlocks();//初始化
      ptr=pvPortMalloc(1024);
	  if(ptr !=NULL)
	  {
	  freemem=xPortGetFreeHeapSize(); 
	  printf("剩余内存 %d \r\n",i,freemem); 
	  }
	  else
	  {
	  printf("获取内存失败\r\n");break;
	  }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

heap_1.c分析:

/**************************************
重要的参数备注:
(1)FreeRTOS  内存堆为:ucHeap[] 大小为 configTOTAL_HEAP_SIZE 

(2)pucAlignedHeap 作为堆栈字节对齐后的起始地址(怎么实现的思考一下)
   pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ])& ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );

(3)configADJUSTED_HEAP_SIZE      堆栈可操作空间,减去对齐单位,防止越界
#define configADJUSTED_HEAP_SIZE	( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) 

保证pucAlignedHeap也是在按照指定内存要求对齐的,通过这里可以知道,初始化pucAlignedHeap时并不是一定等于&ucHeap[0]的,而是会根据字节对齐的要求,在&ucHeap[0]和&ucHeap[portBYTE_ALIGNMENT]之间,这就会导致ucHeap的前几个字节可能会被浪费到,这也是为什么会有一个configADJUSTED_HEAP_SIZE


(4)xNextFreeByte   记录已经使用的内存数量

举个例子:
假设内存堆ucHeap[256]被系统分配为:0x20000603 ~0x20000702  大小为0x100个字节  
因为内存管理要求字节对齐(8),所以pucAlignedHeap 为0x20000608作为后面内存操作的起始地址。   configADJUSTED_HEAP_SIZE=256(0x100)-8 =248个表示可以操作的内存的安全范围。
则结束地址为0x20000700   则内存堆实际的可活动范围为 0x20000608~0x20000700

获取内存:加入申请内存 30个字节  则为其分配32个字节,满足其字节对齐要求
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
xNextFreeByte +=xWantedSize //记录使用内存数量

**************************************/
//pvPortMalloc()实现起来非常简单,需要注意的是分配内存之后不允许再释放
#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

	
//由于可能出现的内存对齐的问题,所以直接舍弃一个对齐单位.
//这样导致实际的数组大小可能小于申请的大小	
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE	( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )  



/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )   // 1 使能自定义堆栈 0编译器决定
	/* The application writer has already defined the array used for the RTOS
	heap - probably so it can be placed in a special segment or address. */
	extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
	static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */


		
/* Index into the ucHeap array. */
static size_t xNextFreeByte = ( size_t ) 0;     //表示已经使用过的内存数量

//  static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] 由系统分配数组
//	configADJUSTED_HEAP_SIZE 为可用的实际大小  xNextFreeByte记录了使用的内存数量
/*---------申请内存实际上是从ucHeap 中获取一块内存,然后返回---------*/

void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn = NULL;
static uint8_t *pucAlignedHeap = NULL;
  
	/* Ensure that blocks are always aligned to the required number of bytes. */
	#if( portBYTE_ALIGNMENT != 1 )
	{
		if( xWantedSize & portBYTE_ALIGNMENT_MASK )
		{
			/* Byte alignment required. */
			xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
		} //如果对齐的宏定义了,则要求申请的数量是  portBYTE_ALIGNMENT 的整数倍。 
	}
	#endif

	vTaskSuspendAll();//挂起调度器任务
	{
		if( pucAlignedHeap == NULL )
		{
			/* Ensure the heap starts on a correctly aligned boundary. */
			pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] )\
			& ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
			//思考一下:为什么取的 ucHeap[ portBYTE_ALIGNMENT ]的地址而不是 ucHeap[0]的地址。
			//首地址需要对齐: 1-7 均要被舍弃 ,取ucHeap[ portBYTE_ALIGNMENT ]可以保证舍弃后,满足8位对齐且不越界
			
		}
     
		//判断 (已使用的 + 新申请的 < 能提供的 )且(已使用的 + 新申请的 >  已使用的)  
		/* Check there is enough room left for the allocation. */
		if( ( ( 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();
		}
	}
	#endif

	return pvReturn;
}
/*-----------------------------------------------------------*/
/*
vPortFree 什么也不做,xNextFreeByte只会增加,不会减小,因此数组中的内存一旦使用,就再也不会被回收
*/

void vPortFree( void *pv )
{
	/* Memory cannot be freed using this scheme.  See heap_2.c, heap_3.c and
	heap_4.c for alternative implementations, and the memory management pages of
	http://www.FreeRTOS.org for more information. */
	( void ) pv;

	/* Force an assert as it is invalid to call this function. */
	configASSERT( pv == NULL );
}




/*-----------------------------------------------------------*/
/* 初始化,由于所有的内存都是静态的,因此只要对xNextFreeByte进行赋值即可 */

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




/*-----------------------------------------------------------*/
/*获取当前可用内存 */
size_t xPortGetFreeHeapSize( void )
{
	return ( configADJUSTED_HEAP_SIZE - xNextFreeByte );
}

猜你喜欢

转载自blog.csdn.net/ZenNaiHeQiao/article/details/82757329