RT-Thread中堆和栈怎么跟单片机内存相联系

        现在RT-Thread+MCU的应用方式越来越普遍,RT-Thread需要配置MCU中的RAM到的系统中,进入系统内存管理,才能提供给基于实时系统的应用程序使用,比如给应用程序提供malloc、free等函数调用功能。在嵌入式软件开发中,我们经常会提到堆和栈,实际上堆和栈都是RAM上的物理内存空间,只是使用方式不同而已。栈和堆都是单片机RAM中一段连续的存储空间,该段空间一般在启动文件或链接脚本中指定,最后在C库的_main函数中进行初始化。STM32中的堆栈内存空间分配就在启动文件中完成:

栈(STACK):由编译器自动分配和释放
堆(HEAP):有的地方也叫堆栈,一般由用户自行分配和释放,因此在分配好使用完成后要及时释放内存,否则会导致系统可用的内存越来越少,我们管这种情况叫做内存泄漏
使用MDK5进行STM32项目开发时,当点击全部编译后会在Build Output窗口生成如下信息: 

那么这些信息究竟是代表什么意思?
Code:代码段,存放程序的代码部分
RO-Data:只读数据段,存放程序中定义的常量
RW-Data:读写数据段,存放初始化为非0值的全局变量
ZI-Data:0数据段,存放初始化为0的全局变量或未初始化的全局变量(程序运行时会对未初始化的全局变量自动清0)需要注意的是,启动文件中定义的STACK和HEAP内存空间都是被包含到ZI-Data中的,如下图片可对比说明:

 

当STACK空间大小设置为0x2000时ZI-Data空间大小为129836Byte,设置为0x1000时ZI-Data空间大小为125740Byte。129836-125740 = 4096 = 0x1000,因此可以说明栈空间是被包含在ZI-Data中的。将HEAP空间大小由0x2000设置为0x1000时,ZI-Data空间大小由129836变为125740,129836-125740 = 4096 = 0x1000,因此可以证明堆空间是被包含在ZI-Data中的。

在工程编译完成后也会生成的对应.map文件,.map文件中详细描述了各个函数在ROM中的存储地址和大小,也可以看到程序中定义的全局变量、全局数组、常量等在RAM中的存储地址和大小,因此.map文件是非常重要的一个文件。在生成的.map的最后几行,也可以看到如下信息:

 那么这些信息究竟是代表什么意思?
RO Size:程序在ROM中的存储大小,包括Code段和RO-Data段
RW Size:程序运行时占用RAM空间的大小,包括RW-Data段和ZI-Data段
ROM Size:程序烧写到ROM上时占用的空间大小,包括Code段和RO-Data段、RW-Data段(这里不包含ZI-Data段是因为ZI-Data段全部是0,将其存储在ROM中毫无意义,因此只需记录ZI-Data段占用的内存空间,在程序运行时在RAM上开辟对应大小的内存空间并将该区域清0即可)

const int ci_max_len = 100;        //RO段
static int si_loop_time = 300;     //RW
char *p1;                          //ZI
int main(void)
{
int i = 0;                       //STACK
char c_say_a[] = "hello world";  //c_say_a存储于STACK,"hello world"存储于RO
char *p= &s[0];                  //STACK
static int si_i = 5;             //RW
char *p2;                        //STACK
p1 = (char *)malloc(100);        //HEAP
p2 = (int *)malloc(100);         //HEAP
...
free(p1);
free(p2);
return 0;
}

Cortex-M3和Cortex-M4在设计之初就考虑到了对OS的高效支持,主要有3点:
1、它们都具有一个内置的简单的向下计数24位计数器SysTick。之所以要在处理器内增加一个定时器,主要是为了提高软件移植的方便性。所有基于Cortex-M3和Cortex-M4内核的处理器具有相同的SysTick定时器,在一种Cortex-M3/M4处理器上实现的OS也能适用于其它Cortex-M3/M4处理器。因此,嵌入式OS的源码可以很容易的移植到其它Cortex-M3/M4内核的处理器上,无需为设备相关的定时器做修改。
2、Cortex-M3内核支持双堆栈机制,即主堆栈MSP和线程堆栈PSP。OS内核和系统中的中断或异常使用MSP,用户创建的多线程任务使用PSP。
3、Cortex-M3/M4内核支持特权模式和非特权模式,可以将用户创建的多线程任务在非特权操作模式中运行,这样可以限制其对一些寄存器的访问,如NVIC、CONTROL寄存器等,以免因为不可靠的程序引起整个系统的崩溃。
        在裸机系统中,所有的变量、函数调用、中断处理等使用的栈空间均是MSP。在使用RTOS的多线程系统中,每个线程都是完全独立互不干扰的,因此需要为每个线程分配独立的栈空间,这个栈空间可以是预先分配好的全局数组(即存储于RW-Data段或ZI-Data段),也可以是动态分配的一段内存空间(注意:这里动态分配的空间不是启动文件(注:启动文件就是单片机相关的.s文件,如startup_hc32f4a0sitb.s)中定义的堆空间,而是由RTOS管理的内存空间),但本质上它们都是RAM上的一段内存空间。在RT-Thread中若需要动态内存管理,则需要先调用board.c--->rt_hw_board_init()--->rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);函数进行动态内存管理范围的配置,即将HEAP_BEGIN和HEAP_END之间的内存空间作为动态内存空间交由RT-Thread进行管理。在RT-Thread Master和RT-Thread Nano版本中,对于rt_system_heap_init()函数调用时填入的参数有些许差异,下面进行对比说明。
RT-Thread Master版本:

 RT-Thread Master版本默认开启RT-Thread中的动态内存分配,并将将HEAP_BEGIN和HEAP_END之间的内存空间作为动态内存空间交由RT-Thread进行管理。其中在board.h文件中有定义,具体如下:

ZI$$Limit是一个链接器导出的符号,代表ZI-Data段的结束,也即程序执行时所占RAM空间的结束地址,也是未使用RAM 空间的起始地址。因此RT-Thread Master版本中会默认将RAM中剩余的内存空间全部交给RT-Thread进行动态内存管理。

RT-Thread Nano版本: 

 RT-Thread Nano版本默认不开启RT-Thread中的动态内存分配,因此凡是涉及到使用RT-Thread动态内存分配的函数都不能使用,如在创建线程时无法使用rt_thread_create()函数,只能使用rt_thread_init()函数等。用户需开启rtconfig.h中的RT_USING_HEAP宏开启使用RT-Thread进行动态内存分配的功能,因为动态内存分配中有使用到信号量,因此还需打开RT_USING_SEMAPHORE宏。rt_system_heap_init()函数中使用的参数rt_heap_begin_get(), rt_heap_end_get()均在board.c文件中有定义,具体如下:

 可以看到RT-Thread Nano版本中是将用户定义好的大小为1024 * 4个字节的内存空间交由RT-Thread进行动态内存管理,而非将RAM中剩余的内存空间全部交给RT-Thread进行动态内存管理。

  这里需要明白的是,程序中并不是将RAM空间用完的,假使RAM为20KByte,实际上只使用了8560Bytes,则剩余的RAM空间全部闲置在那儿。因此在RT-Thread Nano版本中使用数组作为动态内存堆时,可能会有一部分RAM空间是闲置的。

 当把RT_HEAP_SIZE由1024 * 4Byte改为256 * 4Byte时,生成的工程信息中只有ZI-Data发生变化。由11124变为8052,即11124 - 8052 = 3072Byte,和程序中的变化值相等。因此,我们可以理解为:RT-Thread Nano是通过定义全局数组的方式在ZI-Data段占据了一段空间,并将这段空间交由RT-Thread进行动态内存分配。如果不想使用RT-Thread-Nano中使用数组作为动态内存堆的方式,也可以使用和RT-Thread-Master中同样的方法将ZI段结束作为动态内存堆起始地址,将RAM空间结束地址作为动态内存堆的结束地址。这样可以将程序运行所需RAM空间之余的全部空间作为动态内存堆使用,即RAM上没有闲置的内存空间。

编译后生成的.map文件如下所示,可以看到用户自定义的数组消失了,程序使用栈顶地址0x20002b90和RAM空间结束地址0x20005000之间的RAM空间作为RT-Thread的动态内存堆。 

 

当然,RT-Thread Master中也可以使用RT-Thread Nano中默认的使用用户自定义的数组作为动态内存堆的方式。具体如何使用RAM空间,是很灵活的可以由用户自行指定的。当你深入了解RAM空间的分配原理后(一定要研究.map文件,开发中很有用的一个文件),就会发现用户就像是单片机的上帝,上帝可以任意支配手中的资源。而如何让单片机中这些资源按照用户的意愿去分配、去实现既定的功能是我们用户需要去好好研究的。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/945382.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt https请求报错SSL handshake failed 解决思路方法

先执行下面代码 qDebug() << manager.supportedSchemes();bool bSupp QSslSocket::supportsSsl();auto buildVersion QSslSocket::sslLibraryBuildVersionString();QString version QSslSocket::sslLibraryVersionString();qInfo() << bSupp << buildVers…

从CW32L010看HAL库封装方式

原文地址&#xff1a;从CW32L010看HAL库封装方式

锐捷WLAN产品出货量排名第一!

摘要:2024年Q3锐捷WLAN产品出货量排名第一!锐捷多形态Wi-Fi 7产品重磅出击! 近日, IT市场研究和咨询公司IDC发布《IDC中国企业级WLAN市场跟踪报告,2024年Q3》。报告显示,锐捷WLAN产品在2024年Q3出货量位居行业首位。至此,锐捷WLAN产品在2024年的Q1、Q2、Q3均实现了市场出货量的…

【Maven_bugs】The project main artifact does not exist

背景&#xff1a;我想使用 maven-shade-plugin 打一个 fat jar 时报了标题中的错误&#xff0c;使用的命令是&#xff1a;org.apache.maven.plugins:maven-shade-plugin:shade -pl :shade-project。项目结构如下图&#xff0c;我想把子模块 shade-project 打成一个 fat jar&…

React组件化开发

root.render 函数的参数是一个 HTML 元素或一个组件&#xff0c;所以可以将业务逻辑封装到一个组件中&#xff0c;然后传入到 ReactDOM.render 函数中的第一个参数。 在 react 中&#xff0c;可以使用类的方式封装组件&#xff1a; 定义一个类(类名大写&#xff0c;组件的名称…

《以太全光:依循标准规范,奏响医院网络建设 “光” 之乐章》

在当今数字化浪潮的席卷下,医疗行业正以前所未有的速度踏上智能化转型的征程。在这场变革中,网络架构作为支撑医疗行业的基础设施,扮演着至关重要的角色。那么,究竟哪种网络架构才是医疗行业网络建设的理想选择呢? 近期,住房城乡建设部发布的《综合医院建筑设计标准》给出了明…

【网络安全实验室】基础关实战详情

须知少时凌云志,曾许人间第一流 1.key在哪里 url&#xff1a;http://rdyx0/base1_4a4d993ed7bd7d467b27af52d2aaa800/index.php 查看网页源代码的方式有4种&#xff0c;分别是&#xff1a;1、鼠标右击会看到”查看源代码“&#xff0c;这个网页的源代码就出现在你眼前了&…

【Qt】容器控件、布局管理控件

目录 容器控件 QGroupBox QTabWidget 布局管理控件 QVBoxLayout 例子&#xff1a; QHBoxLayout 例子&#xff1a; QGridLayout 例子&#xff1a; 例子&#xff1a; QFormLayout 例子&#xff1a; QSpacerItem 例子&#xff1a; 容器控件 QGroupBox 表示一个带有…

Lucene 漏洞历险记:修复损坏的索引异常

作者&#xff1a;来自 Elastic Benjamin Trent 有时&#xff0c;一行代码需要几天的时间才能写完。在这里&#xff0c;我们可以看到工程师在多日内调试代码以修复潜在的 Apache Lucene 索引损坏的痛苦。 做好准备 这篇博客与往常不同。它不是对新功能或教程的解释。这是关于花…

【最新】沃德协会管理系统源码+uniapp前端+环境教程

一.系统介绍 一款基于FastAdminThinkPHPUniapp开发的商协会系统&#xff0c;新一代数字化商协会运营管理系统&#xff0c;以“智慧化会员体系、智敏化内容运营、智能化活动构建”三大板块为基点&#xff0c;实施功能全场景覆盖&#xff0c;一站式解决商协会需求壁垒&#xff0…

STM32 软件I2C读写

单片机学习&#xff01; 目录 前言 一、软件I2C读写代码框架 二、I2C初始化 三、六个时序基本单元 3.1 引脚操作的封装和改名 3.2 起始条件执行逻辑 3.3 终止条件执行逻辑 3.4 发送一个字节 3.5 接收一个字节 3.5 发送应答&接收应答 3.5.1 发送应答 3.5.2 接…

LeetCode - Google 校招100题 第6天 回溯法(Backtracking) (8题)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/144743505 LeetCode 合计最常见的 112 题: 校招100题 第1天 链表(List) (19题)校招100题 第2天 树(Tree) (21题)校招100题 第3天 动态规划(DP) (20题)

【PCIe 总线及设备入门学习专栏 4.5 -- PCIe Message and PCIe MSI】

文章目录 PCIe Message 与 MSIPCIe Message 和 MSI 的作用与关系MSI 的配置与寄存器MSI 和 ARM GIC 的关系示例&#xff1a;MSI 在 ARM GIC 的实际应用总结 PCIe Message 与 MSI 本文将介绍 PCIe message 的作用以及message 与 MSI 的关系&#xff0c;再介绍 MSI 如何配置以及…

ThinkPHP 8高效构建Web应用-第一个简单的MVC应用示例

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 我们先实现一…

NSSCTFpwn刷题

[SWPUCTF 2021 新生赛]nc签到 打开附件里面内容 import osart (( "####!!$$ ))#####!$$ ))(( ####!!$:(( ,####!!$: )).###!!$:##!$:#!!$!# #!$: #$#$ #!$: !!!$:\ "!$: /\ !: /"\ : /"-."-/\\\-."//.-"…

Vue多页面路由与模版解析

上篇文章中我们成功打包并输出了多页文件&#xff0c;而构建一个多页应用能够让我们进一步了解项目配置的可拓展性&#xff0c;可以对学习 Vue 和 webpack 起到强化训练的效果&#xff0c;本文将在此基础上主要针对多页路由及模板的配置进行系列的介绍。 路由配置 1. 跳转 在…

UE5材质节点SimpleGrassWind

SimpleGrassWind节点可以模拟树叶扰动&#xff0c;或小草晃动效果 用来做风格化树、风格化草效果很好 主要节点 前三个节点分别用来控制&#xff0c;风强度&#xff0c;风重力&#xff0c;风速度&#xff0c;WPO是世界位置偏移

macrodroid通过http请求控制手机运行宏

macrodroid adb命令 adb shell pm grant com.arlosoft.macrodroid android.permission.WRITE_SECURE_SETTINGS例:http请求手机播放指定MP3文件 声音素材_电量过低提醒 新建一个宏 添加触发器-连接-http服务器请求 路径随意填,最好不要有特殊符号,不然浏览器识别链接会出错,…

单片机中运行多个定时器

在单片机的裸机编程环境中&#xff0c;同时运行多个定时器是完全可行的&#xff0c;但需要注意一些关键点以确保系统的稳定性和效率。以下是一些考虑因素和实现方法&#xff1a; 1. 硬件支持 定时器数量&#xff1a;首先确认您的单片机是否具备足够的定时器资源。大多数现代…

快速上手LangChain(一)

文章目录 LangChain一、背景二、什么是langchain三、Components 组件Prompt templates 提示模板Chat models 聊天模型Messages 消息Document loadersText Spltters 文本分割Vectorstores 向量数据库 四、langchain基础概念Tool calling 工具调用&#xff08;1&#xff09; 工具…