FreeRTOS实时操作系统(十六)内存管理与堆栈溢出

系列文章

FreeRTOS实时操作系统(一)RTOS的基本概念

FreeRTOS实时操作系统(二)任务创建与任务删除(HAL库)

FreeRTOS实时操作系统(三)任务挂起与恢复

FreeRTOS实时操作系统(四)中断任务管理

FreeRTOS实时操作系统(五)进入临界区、任务调度器挂起与恢复

FreeRTOS实时操作系统(六)列表与列表项

FreeRTOS实时操作系统(七)时间片调度及RTOS的滴答定时器

FreeRTOS实时操作系统(八)任务状态查询及时间统计函数

FreeRTOS实时操作系统(九)时间延时函数及消息队列

FreeRTOS实时操作系统(十)信号量

FreeRTOS实时操作系统(十一)队列集

FreeRTOS实时操作系统(十二)事件标志组

FreeRTOS实时操作系统(十三)任务通知

FreeRTOS实时操作系统(十四)软件定时器

FreeRTOS实时操作系统(十五)Tickless低功耗模式

FreeRTOS实时操作系统(十六)内存管理



内存管理

动态创建:自动地从 FreeRTOS 管理的内存堆中申请创建对象所需的内存,并且在对象删除后,
可将这块内存释放回FreeRTOS管理的内存堆
静态创建:需用户提供各种内存空间,并且使用静态方式占用的内存空间一般固定下来了,即使任务、队列等被删除后,这些被占用的内存空间一般没有其他用途

前面使用的一些创建队列、信号量等,采用的都是动态创建的方式,比起静态的方式,更加简便、灵活。

标准C库也提供了函数malloc()和free()实现动态申请和释放内存,但是没有线程安全的相关机制,内存碎片化等缺点

FreeRTOS提供了五种内存管理算法:(介绍heap_4)
在这里插入图片描述
heap_2 内存管理算法使用最适应算法,找出最小的,满足条件的内存碎片,但不能合并空闲内存块

heap_4使用了首次适应算法(第一个满足条件的内存块),也支持内存的申请与释放,并且能够将空闲且相邻的内存进行合并,从而减少内存碎片的现象。

heap_5 内存管理算法是在 heap_4 内存管理算法的基础上实现的,但是 heap_5 内存管理算法在 heap_4 内存管理算法的基础上实现了管理多个非连续内存区域的能力,heap_5 内存管理算法默认并没有定义内存堆 ,需要用户手动指定内存区域的信息,对其进行初始化。

API函数

函数描述
void * pvPortMalloc( size_t xWantedSize );申请内存
void vPortFree( void * pv );释放内存
size_t xPortGetFreeHeapSize( void );获取当前空闲内存的大小
  1. void * pvPortMalloc( size_t xWantedSize );
    xWantedSize:申请的内存大小,以字节为单位;
    返回值:返回一个指针 ,指向已分配大小的内存。如果申请内存失败,则返回 NULL。

  2. void vPortFree( void * pv );
    *pv:指针指向一个要释放内存的内存块;

  3. size_t xPortGetFreeHeapSize( void );
    返回值:返回当前剩余的空闲内存大小

实验测试

void task2( void * pvParameters )
{
	uint8_t t = 0;
    uint8_t * buf = NULL;
    while(1)
    {
			buf = pvPortMalloc(30);                 /* 申请内存 */
			if(buf != NULL)
			{
				printf("申请内存成功!\r\n");
			}
			else 
				printf("申请内存失败\r\n");

			if(buf != NULL)
			{
				vPortFree(buf);                     /* 释放内存 */
				printf("释放内存!!\r\n");
		    } 
		
		if(t > 50)
		{
			t = 0;
			printf("剩余的空闲内存大小为:%d\r\n",xPortGetFreeHeapSize());
		}	
		t++;		
		vTaskDelay(20);
    }
}

测试成功,这里的buf存放的是申请后的地址,所以如果申请一次内存后,多次释放的时候就会出现问题。

这里申请的是30个字节的大小,但是在打印的时候,申请释放前后的总的占用大小差值并不是30,因为还有一些句柄啥的会创建

堆栈溢出

堆栈溢出检查会增加上下文切换的开销,因此建议只在开发或测试阶段使用此检查。

在 RTOS 内核溢出检查开始之前,某些处理器可能会因堆栈损坏而发生故障或异常

方法一:
在 RTOS 内核使任务退出运行状态后,堆栈可能达到其最大(最深)值, 因为此时的堆栈会包含任务上下文。 此时,RTOS 内核可以检查处理器堆栈指针是否仍在有效堆栈空间内。 如果堆栈指针包含超出有效堆栈范围的值, 则调用堆栈溢出钩子函数。
此方法很快,但不能保证可以捕获所有堆栈溢出。 将 configCHECK_FOR_STACK_OVERFLOW 设置为 1 即可使用此方法。

方法二:
任务首次创建时,其堆栈会填充一个已知值。 任务退出运行状态时,RTOS 内核 可以检查有效堆栈范围内的最后 16 个字节,以确保这些已知值未被任务或中断活动 覆盖。 如果这 16 个字节中的任何一个不再为初始值,则调用堆栈溢出钩子函数。
这种方法比方法 1 效率低,但仍然相当快。 它很可能会捕获堆栈溢出, 但仍无法保证能够捕获所有溢出。

将 configCHECK_FOR_STACK_OVERFLOW 设置为 2 即可使用此方法。

方法三:
将 configCHECK_FOR_STACK_OVERFLOW 设置为 3 即可使用此方法。
此方法仅适用于选定的端口。将启用 ISR 堆栈检查。检测到 ISR 堆栈溢出时, 将触发断言。请注意,在这种情况下不会调用堆栈溢出钩子函数, 因为它只针对任务堆栈,而不是 ISR 堆栈。

如果 configCHECK_FOR_STACK_OVERFLOW 未设置为 0 ,则应用程序必须提供堆栈溢出钩子函数。 该钩子函数必须 命名为 vApplicationStackOverflowHook(),并具有以下原型:

void vApplicationStackOverflowHook( TaskHandle_t xTask,
                                    char *pcTaskName );

xTask 和 pcTaskName 参数分别将违规任务的句柄和名称传递给该钩子函数。 但请注意,根据溢出的严重程度,这些参数本身可能会损坏,在这种情况下, 可直接检查 pxCurrentTCB 变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值