获取 FreeRTOS 栈空间大小及其高水位线

获取 FreeRTOS 栈空间大小及其高水位线

概述

如在FreeRTOS 创建任务的博客中所述的那样,RTOS 中的任务需要一块存储空间存储 TaskCode 中的临时变量。在创建任务时,可以通过函数中的 StackDepth 指定该空间的大小:

BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pxCreatedTask)

通常 stack 使用 RAM 上的一块存储空间,考虑到 RAM 空间极为有限,stack size 的配置大小就显得极为重要了。
若 stack size 配置的太小,当 TaskCode 中局部变量过多时容易造成存储空间不足,出现”栈溢出“的风险,导致任务出现异常。

若 stack size 配置的太大,则容易对有限的 RAM 空间造成浪费。

因此,本节对评估 Task 的 stack size 的一些方法进行总结,期望大家通过实践写出即节省 RAM 又稳定可靠的 Task Code.

需求及功能解析

每个任务都有自己的堆栈(简称栈、stack),堆栈的总大小在创建任务的时候就确定了,下述两个函数用于检查任务从创建好到现在的**历史剩余最小值,**这个值越小说明任务堆栈溢出的可能性就越大!FreeRTOS 把这个历史剩余最小值叫做“高水位线(High Water Mark,简称 HWM)”。该部分函数相对来说会多耗费一点时间,所以在代码调试阶段可以使用,产品发布的时候最好不要使用。评估 Task 的 stack size 可以使用下述两个函数:

1)

/*
* 参数:要查询的任务的任务句柄,当这个参数为 NULL 的话说明查询自身任务(即调用函数 uxTaskGetStackHighWaterMark()的任务)的“高水位线”。
*/
UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask)  

返回值:

在标准的 FreeRTOS 中上述函数返回的值是以字表示的高水位线(例如,在32位机器上,返回值1表示堆栈的4个字节未使用)。如果返回值为零,则任务可能已溢出其堆栈。如果返回值接近于零,则任务已接近溢出其堆栈。*在 ESP-IDF 中注意返回的是 字节 而不是字。*

2)

configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2(TaskHandle_t xTask)

uxTaskGetStackHighWaterMark2()是uxTaskGetStackHighWaterMark()的一个版本,它返回用户可定义的类型,以消除8位体系结构上UBaseType_t类型的数据类型宽度限制。

任务使用的堆栈将随着任务的执行和中断的处理而增长和收缩。uxTaskGetStackHighWaterMark()返回自任务开始执行以来任务可用的最小剩余堆栈空间量,即任务堆栈达到最大(最深)值时未使用的堆栈量。这就是所谓的烟囱“高水位线”。

注意:返回值更新的前提是有新的最小值出现,否则即便初始化新的临时变量,可能也不会刷新这个 HighWaterMark 的值(因为 stack size 减小了,但是没有到刷新最小值的地步)。

注意:Task 本身的 handle、状态管理不消耗这个 stack size(内部用的是malloc),但是 printf() 这个函数是消耗 stack size 的。

感兴趣的老铁可以增加临时变量的 size,观察该函数的变化。

示例解析

log 输出如下:

This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 294424 bytes
TASK1: wm1 = 1744
Task2 stk_wm = 1596
TASK1: wm2 = 496
TASK1: wm3 = 496
Task3 stk_wm = 3672

示例给出了使用两个函数查询任务 高水位线的使用方法。随着 Task1 中的局部变量被使用,task1 的高水位线被更新为更小的值。task2、task3 的代码一样,但创建任务时指定的 stack size 不一样,因此可用的栈空间也不一样。

讨论

通过对任务栈空间的理解及测试方法的了解,我们给出下述建议:

1)当某个 task 最小剩余 task 栈空间比较大时,适当减小 xTaskCreate 创建该 task 时给定的第三个参数值,可节约 RAM,以优化系统内存。

2)当某个 task 最小剩余 task 栈空间比较小时,适当增大 xTaskCreate 创建该 task 时给定的第三个参数值,可降低 task 栈溢出风险。

3)如果对 SDK 没有深入了解,不要修改 系统 task 分配的最大可用栈空间。

4)不要在系统 task 的 callback 函数里,添加过多代码,不要添加阻塞操作。
因为系统 task 通常都是经过优化配置的,如果代码深度较大,容易造成 task 栈溢出;
如果有阻塞操作,将导致该系统 task 接下来逻辑无法执行,甚至有死锁的可能。
例如:
sniffer 的 callback 函数: wifi_promiscuous_cb_t cb
WiFi callback 函数: system_event_cb_t cb

5)占用空间较大的变量,尽可能通过 malloc/calloc 等动态申请释放,以提高栈空间利用率。

总结

1)通过 uxTaskGetStackHighWaterMark()uxTaskGetStackHighWaterMark2()可以评估任务自创建以来的最小剩余栈空间的大小,其返回值以字节为单位。

2)在任务创建时合理的分配栈空间大小对节省RAM 空间、保证任务运行的稳定性非常重要。

3)系统自动创建的任务中,也要注意栈空间大小的限制,在系统 task 中的回调函数中不能添加过多代码,不要添加任何阻塞操作,慎用延时。

4) 占用空间较大的变量,尽可能通过 malloc/calloc 等动态申请释放,以提高栈空间利用率。

资源链接

1)Learning-FreeRTOS-with-esp32 系列博客介绍
2)对应示例的 code 链接 (点击直达代码仓库)

3)下一篇:RTOS任务状态总结及查看 RTOS 任务的状态

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FreeRTOS提供了空间溢出检测的功能,但它会引入任务上下文切换的开销,因此仅推荐在应用开发或测试阶段使用。这个功能可以帮助用户减少代码中的错误并提应用程序代码的质量。每个任务都独立维护自己的空间空间总量在任务创建时进行设定。通过使用函数uxTaskGetStackHighWaterMark(),可以查询指定任务的运行历史中,其空间还差多少就要溢出,这个值被称为空间的"线"。在FreeRTOS源码的tasks.c文件中,可以找到taskCHECK_FOR_STACK_OVERFLOW函数在任务上下文切换时被调用,这意味着软件检测溢出的方式具有一定的滞后性,只有在任务发生上下文切换时才会进行检测,而不能立即检测到任务堆栈溢出的问题。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *3* [FreeRTOS中的任务堆栈溢出检测机制](https://blog.csdn.net/ybhuangfugui/article/details/120897699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [freeRTOS中文实用教程6--错误排查](https://blog.csdn.net/weixin_30784501/article/details/97942628)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物联网老王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值