一、一个查任务栈用量的 API
嵌入式开发里,任务栈开多大是个经典难题——开小了溢出死机,开大了浪费宝贵的 RAM。FreeRTOS 给了一个现成的检查工具:
uxTaskGetStackHighWaterMark():返回任务栈的"历史最小剩余空间"(栈高水位),单位是字(word,STM32 上 1 字 = 4 字节)。
返回值越小→ 栈用得越多
返回0→ 剩余空间归零,说明栈曾经溢出过
vTaskGetInfo():更完整的接口,一次性拿到任务状态、优先级、栈高水位等信息。
CubeMX 里启用:Middleware → FREERTOS → Config parameters → INCLUDE parameters,把INCLUDE_uxTaskGetStackHighWaterMark设为Enabled。
我实测的一组数据(高水位,单位:字):
场景 | 高水位 | 说明 |
|---|---|---|
不调 printf,第一次调用 | 118 | 变量声明在循环外,整个函数栈帧一直占着 |
不调 printf,稳定后 | 106 | 循环内变量被复用,栈占用更稳定 |
调 printf 后 | 84 | 比上面少 22 字 ≈ 88 字节,这就是 printf 的栈消耗 |
二、高水位是怎么数出来的:0xA5 填充法
原理非常朴素:
创建任务时,FreeRTOS 把整块任务栈预填充 0xA5这个固定值;
任务运行时会往栈里写数据,把 0xA5 覆盖掉;
调用高水位 API 时,从栈底往上扫描,数一数还有多少连续的 0xA5没被覆盖——这个数量就是"从来没被用到过的栈空间"。
由这个机制还能得到一个编程启示:变量的声明位置会影响栈峰值。声明在循环外,变量在整个函数生命周期里都占着栈帧;声明在循环内,编译器可能复用空间,栈峰值更低、更稳定。