当前位置: 首页 > news >正文

FreeRtos——20、任务栈大小确认以及栈溢出与检测

一、任务栈大小确认

在FreeRTOS的应用设计中,每个任务都需要独立的栈空间,而且每个任务需要的栈大小也是不同的将如下的几个选项简单的累加就可以得到一个粗略的栈大小:

1、函数

  • 局部变量
  • 函数形参(针对函数嵌套)
  • 函数返回地址(针对函数嵌套)
  • 函数内部的状态保存

2、任务切换
3、发生中断

实际应用中将这些都加起来是一件非常麻烦的工作,上面这些栈空间加起来的总和只是栈的最小需求实际分配的栈大小可以在最小栈需求的基础上乘以一个安全系数,一般取 1.5-2。
上面的计算是我们用户可以确定的栈大小,项目应用中还存在无法确定的栈大小,比如调用printf函数就很难确定实际的栈消耗。又比如通过函数指针实现函数的间接调用,因为函数指针不是固定的指向-个函数进行调用,而是根据不同的程序设计可以指向不同的函数,使得栈大小的计算变得比较麻烦。
另外还要注意一点,建议不要编写递归代码,因为我们不知道递归的层数,栈的大小也是不好确定的。

建议:
可以事先给任务分配一个大的栈空间,然后通过第二讲介绍的调试方法打印任务栈的使用情况,运行段时间就会有个大概的范围了,再乘以安全系数,即可得到需要使用的空间。

如下图:Test1-3使用的栈空间:(128-106)=22 words,乘以安全系数,分配33 words即可

二、任务栈溢出与检测

1、任务栈溢出

上面说了如何确定任务栈的大小,那什么又是栈溢出呢?简单的说就是用户分配的栈空间不够用了溢出了。

下面我们举一个简单的实例,栈生长方向从高地址向低地址生长(M4和 M3是这种方式)

① 上图标识 1 的位置是 RTOS 的某个任务调用了函数 test()前的 SP 栈指针位置

② 上图标识 2的位置是调用了函数 test 需要保存返回地址到栈空间。这一步不是必须的,对于 M3和M4 内核是先将其保存到 LR 寄存器中,如果 LR 寄存器中有保存上一级函数的返回地址,需要将 LR 寄存器中的内容先入栈

③ 上图标识 3 的位置是局部变量 inti和 int array[10]占用的栈空间,但申请了栈空间后已经越界了。这个就是所谓的栈溢出了。如果用户在函数 test 中通过数组 array 修改了这部分越界区的数据且这部分越界的栈空间暂时没有用到或者数据不是很重要,情况还不算严重,但是如果存储的是关键数据,会直接导致系统崩溃

④ 上图标识 4 的位置是局部变量申请了栈空间后,栈指针向下偏移(返回地址+变量 i+10 个数组元素)*4=48 个字节

⑤ 上图标识 5 的位置可能是其它任务的栈空间,也可能是全局变量或者其它用途的存储区,如果 test函数在使用中还有用到栈的地方就会从这里申请,这部分越界的空间暂时没有用到或者数据不是很重要,情况还不算严重,但是如果存储的是关键数据,会直接导致系统崩溃

2、FreerRTOS栈溢出检测机制

FreeRTOS 提供了两种栈溢出检测机制,这两种检测都是在任务切换时才会进行:

方法一

在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函数(钩子函数的主要作用就是对原有函数的功能进行扩展,用户可以根据自己的需要往里面添加相关的测试代码)

void vApplicationStackOverflowHook( TaskHandle t xTask, signed char *pcTaskName );

用户可以在钩子函数里面做一些处理。这种方法不能保证所有的栈溢出都能检测到。比如任务在执行的过程中出现过栈溢出。任务切换前栈指针又恢复到了正常水平,这种情况在任务切换的时候是检测不到的。又比如任务栈溢出后,把这部分栈区的数据修改了,这部分栈区的数据不重要或者暂时没有用到还好,但如果是重要数据被修改将直接导致系统进入硬件异常,这种情况下,栈溢出检测功能也是检测不到的。

使用方法一需要用户在 FreeRTOSConfig.h 文件中配置如下宏定义

#define configCHECK_FOR_STACK_OVERFLOW 1

方法二:

任务创建的时候将任务栈所有数据初始化为 0xa5,任务切换时进行任务栈检测的时候会检测未尾的 16个字节是否都是 0xa5,通过这种方式来检测任务栈是否溢出了。相比方法一,这种方法的速 度稍慢些,但是这样就有效地避免了方法一里面的部分情况。不过依然不能保证所有的栈溢出都能检测到,比如任务栈末尾的 16 个字节没有用到,即没有被修改,但是任务栈已经溢出了,这种情况是检测不到的。另外任务栈溢出后,任务栈末尾的 16 个字节没有修改,但是溢出部分的栈区数据被修改了,这部分栈区的数据不重要或者暂时没有用到还好,但如果是重要数据被修改将直接导致系统进入硬件异常这种情况下,栈溢出检测功能也是检测不到的。

使用方法二需要用户在 FreeRTOSConfig.h 文件中配置如下宏定义

#define configCHECK_FOR_STACK_OVERFLOW 2

三、实例

使用方法1,检测堆栈的指针

1、创建一个按键检测任务

/* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ //手动动态创建任务 xTaskCreate( (TaskFunction_t)KEY_Task, "KEY", 128, NULL, osPriorityHigh, &KEYHandle ); /* USER CODE END RTOS_THREADS */

2、在按键检测这个任务中,使用较大的数组,让他越界

void KEY_Task(void const * argument) { /* Infinite loop */ for(;;) { //按键检测 KEY.GetKeyCode(); //KEY1处理 if(KEY.KeyCode == KEY1) { printf("KEY1按下\r\n"); int16_t i; uint8_t Buf[1024]; //前面创建任务的时候是128字,也就是512个字节,这里我们数组占1024个字节,是越界的 for(i = 1023; i >= 0; i--) { Buf[i] = 0x55; vTaskDelay(1); } } //阻塞延时20ms osDelay(20); } }

3、在钩子函数中打印哪个任务溢出了

4、系统跑起来以后,就会开始报发生栈溢出,因为数组太大了,但是不会死机,这是因为没有去写数据,不会改变其他位置的内存,不会产生系统错误

5、按下按键1,就会执行数组那块,就会产生系统错误了,因为检测到按键1,会开始写数据,此时写数据就会改变其他位置的内存了,就会产生系统错误

此时会调用stm32f1xx_it.c文件中的HardFault_Handler函数,系统错误函数

http://www.jsqmd.com/news/470532/

相关文章:

  • COMSOL压电横波检测裂纹:楔块为亚克力塑料,PZT-5H压电片自发自收检测模型
  • ai驱动的黑盒web扫描器欢迎补充
  • ERP上线前一晚,项目组必做的最后检查清单
  • 黄金短期上涨势头不佳受什么因素影响?
  • 2026年口碑好的网版工厂推荐:丝印网版/印刷网版/钢丝网网版源头工厂推荐 - 行业平台推荐
  • Flume01:大数据日志收集与传输利器
  • 初学算法打卡第一天:入门 DP问题
  • vue表格数据分组后如何同时实现筛选功能
  • 仿muduo库实现高并发服务器---线程池模块Eventloop的实现
  • CCP基本命令—选择标定数据页、获取DAQ列表大小
  • 导入Rsoft接口库
  • 网络通信与 TCP/IP 五层协议模型详解
  • 2026年质量好的异性拉伸件公司推荐:五金拉伸件生产厂家推荐几家 - 行业平台推荐
  • No.103.基于博途的PLC三种模式通行时间可调的复杂路口交通灯程序设计与仿真,带登录系统登...
  • 2026年比较好的食品生产线公司推荐:麦片生产线/糖果生产线/复合薯片生产线值得信赖的生产厂家 - 行业平台推荐
  • java基于springboot的毕业生招聘职位推荐系统设计
  • java关键字之final学习
  • 基于Vue.js的电商前端模板:Vue-Dashboard-Template的设计与实现
  • 2026年比较好的包装机公司推荐:给袋包装机/巧克力包装机/糖果枕式包装机工厂直供哪家专业 - 行业平台推荐
  • Windows应用程序漏洞及防御
  • 2025 1-12
  • 线缆中的正向、反向、同向、异向的具体意思是什么?
  • 低温传感器质量检测的具体步骤
  • 从2026消费趋势洞察看春节礼品推荐方向,附选购清单 - yangyuan-shunfeng
  • Day2-MySQL-SQL-1
  • 2026年重庆特色美食评测:这几家口碑老店值得专程前往,特色美食/火锅店/社区火锅/火锅/美食,特色美食品牌推荐 - 品牌推荐师
  • 校园跑腿服务平台的技术实现与案例分析
  • 为什么要深入学习JVM底层原理
  • 快看2026年2月国内热门智适应动力模块工厂推荐排行,回风箱式电子除尘净化器/空调机组,智适应动力模块供应厂家选哪家 - 品牌推荐师
  • Whatever