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

嵌入式面试八股文(十二)·FreeRTOS中·堆和栈

目录

1.  堆和栈

1.1  堆

1.2  栈

1.3  堆和栈的区别

1.3.1  分配方式

1.3.2  分配效率

1.3.3  生长方向

1.3.4  空间管理

1.3.5  存放内容


1.  堆和栈

1.1  堆

        堆是一块用于动态分配内存的区域,用于存储程序运行时动态创建的对象。堆的大小可以在程序运行时动态调整。

        堆由开发人员分配和释放, 若开发人员不释放,程序结束时由 OS 回收。

        堆的分配和释放需要调用相应的函数,如malloc()和free函数。

        在FreeRTOS中堆用来分配任务、队列、信号量、互斥量等内核对象的内存。

        FreeRTOS 提供了 5 种堆管理实现(heap_1 到 heap_5),开发者可通过 FreeRTOS/Source/portable/MemMang 目录下的文件选择。

        堆大小:在 FreeRTOSConfig.h 中通过 configTOTAL_HEAP_SIZE 定义(单位:字节)。 

void *pvPortMalloc(size_t xSize);  // 分配内存
void vPortFree(void *pv);          // 释放内存

        堆的内存地址生长方向与栈相反,由低到高,但需要注意的是,后申请的内存空间并不一定在先申请的内存空间的后面,即 p2 指向的地址并不一定大于 p1 所指向的内存地址,原因是先申请的内存空间一旦被释放,后申请的内存空间则会利用先前被释放的内存,从而导致先后分配的内存空间在地址上不存在先后关系。堆中存储的数据若未释放,则其生命周期等同于程序的生命周期。

int main() {// C 中用 malloc() 函数申请char* p1 = (char *)malloc(10);cout<<(int*)p1<<endl;		//输出:00000000003BA0C0// 用 free() 函数释放free(p1);// C++ 中用 new 运算符申请char* p2 = new char[10];cout << (int*)p2 << endl;		//输出:00000000003BA0C0// 用 delete 运算符释放delete[] p2;
}

1.2  栈

        栈是一种用于存储局部变量和函数调用信息的数据结构。栈的大小在程序编译时确定,通常较小。

        栈由操作系统自动分配释放 ,用于存放函数的参数值、局部变量等,其操作方式类似于数据结构中的栈。参考如下代码:

int main() {int b;				//栈char s[] = "abc"; 	//栈char *p2;			//栈
}

        栈的内存地址生长方向与堆相反,由高到底,所以后定义的变量地址低于先定义的变量,比如上面代码中变量 s 的地址小于变量 b 的地址,p2 地址小于 s 的地址。

        栈中存储的数据的生命周期随着函数的执行完成而结束。

        在FreeRTOS中,栈大小:在创建任务时通过 usStackDepth 参数指定(单位:sizeof(StackType_t))。

xTaskCreate(TaskFunction, "Task", usStackDepth, NULL, priority, &Handle);

         栈的分配方式有两种类型:

  • 静态栈:预先分配固定大小的数组(StaticTask_t)。
  • 动态栈:从堆中动态分配内存(默认方式)。

FreeRTOS菜鸟入门(七)·创建任务·静态任务创建-CSDN博客

FreeRTOS菜鸟入门(八)·创建任务·动态任务创建_freertos 创建动态任务的堆栈-CSDN博客

1.3  堆和栈的区别

1.3.1  分配方式

堆都是动态分配的,由程序员手动控制,堆的分配可以在任意时刻进行,不需要遵循特定的顺序。

栈有 2 种分配方式:静态分配和动态分配。

        静态分配是由操作系统完成的,由编译器自动控制,栈的分配在编译时确定,无法在运行时改变,比如局部变量的分配。

        动态分配由alloca()函数分配,但是栈的动态分配和堆是不同的,它的动态分配是由操作系统进行释放,无需我们手工实现。

        栈还用于中断时的保存现场和恢复现场。

简单来说,

堆的分配和释放由程序员控制,分配后可变;

栈的分配和释放由编译器控制,分配后不可变。

1.3.2  分配效率

        堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。

        栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。

堆的分配效率较低,需要在运行时动态分配和释放。

栈的分配效率较高,由编译器在编译时确定分配大小。

1.3.3  生长方向

堆的生长方向向上,内存地址由低到高;

对于堆需要注意:后申请的内存空间并不一定在先申请的内存空间的后面,原因是先申请的内存空间一旦被释放,后申请的内存空间则会利用先前被释放的内存,从而导致先后分配的内存空间在地址上不存在先后关系。

栈的生长方向向下,内存地址由高到低。

1.3.4  空间管理

堆的空间管理由程序员手动控制,需要注意内存泄漏和内存碎片的问题。

栈的空间管理由编译器自动控制,无效程序员关注。

1.3.5  存放内容

堆:

任务控制块(TCB):TaskHandle_t 指向的结构体,包含任务状态、优先级、栈指针等信息。

任务栈空间(动态分配时):通过 xTaskCreate() 创建任务时,从堆中分配栈内存。

队列(Queue):xQueueCreate() 创建的队列数据结构和存储区域。

信号量/互斥量:xSemaphoreCreateBinary()、xSemaphoreCreateMutex() 等创建的同步对象。

定时器(Timer):xTimerCreate() 创建的软件定时器结构。

动态分配的缓冲区:用户通过 pvPortMalloc() 手动申请的内存块。

栈:

局部变量:函数内定义的变量(如 int temp)。

函数调用链:返回地址、函数参数、寄存器保存值(中断或任务切换时)。

中断现场:发生中断时,CPU 自动压栈的寄存器状态(如 R0-R12, LR, PC)。

表达式计算:算术运算的中间结果。

拓展:

嵌入式面试八股文(十一)·FreeRTOS相关题目_freertos习题-CSDN博客

千题千解·嵌入式工程师八股文详解_时光の尘的博客-CSDN博客

http://www.xdnf.cn/news/193969.html

相关文章:

  • Oracle备份和恢复
  • 论文速报《Enhancing Autonomous Driving Systems...:LLM-MPC混合架构增强自动驾驶》
  • C语言基础—(函数,指针与形参实参,字符串与指针,结构体)
  • Golang|使用函数作为参数和使用接口的联系
  • 23种设计模式
  • STM32N6570-DK ISP调试
  • UDP 报文结构与注意事项总结
  • 每日c/c++题 备战蓝桥杯(P1093 [NOIP 2007 普及组] 奖学金)
  • 勘破养生伪常识,开启科学养生新篇
  • 发那科机器人(基本操作、坐标系、I/O通信)
  • JVM——引入
  • STM32裸机编程架构与思路
  • LangChain4j +DeepSeek大模型应用开发——2 接入其他大模型
  • 练习普通话,说话更有节奏
  • Odoo 18 中计划、待办、项目管理模块解析
  • re题(49)BUUCTF-crackMe
  • 【深度剖析】贵州茅台的数字化转型(2025)(中1)
  • Spring的BeanFactory和FactoryBean的区别
  • springboot dev process
  • JVM模型、GC、OOM定位
  • [250428] Nginx 1.28.0 发布:性能优化、安全增强及新特性
  • wps批注线条怎么取消去掉wps批注后有竖线
  • CentOS7——Docker部署java服务
  • 基于常微分方程的神经网络(Neural ODE)
  • 如何通过Google Chrome增强网页内容的安全性
  • 低空经济无人机创新实训室解决方案
  • 亚马逊环保标识运营指南:抢占流量新赛道的6大策略解析
  • 读论文《Deep learning-assited pulsed discharge plasma catalysis modeling》2023 ECM
  • Android Studio 2024版,前进返回按钮丢失解决
  • springboot项目之websocket的坑:spring整合websocket后进行单元测试后报错的解决方案