写在开头
代码编译后提示信息可以看到的内容
1、Code :是代码占用的空间,存储到flash【Rom】中的程序代码
2、RO-data:是 Read Only 只读常量的大小,如const型。用来存储程序的指令和常量,保存在ROM中。
3、RW-data:是(Read Write) RW是可读可写变量,就是初始化时候就已经赋值了的,RW + ZI就是你的程序总共使用的RAM字节数。
4、ZI-data:是(Zero Initialize) 没有初始化的可读写变量的大小,就是程序中用到的变量并且被系统初始化为0的变量的字节数,keil编译器默认是把你没有初始化的变量都赋值一个0,这些变量在程序运行时是保存在RAM中的。
Total ROM Size (Code + RO Data + RW Data)这样所写的程序占用的ROM的字节总数,也就是说程序所下载到ROM flash 中的大小。为什么Rom中还要存RW,因为掉电后RAM中所有数据都丢失了,每次上电RAM中的数据是被重新赋值的,每次这些固定的值就是存储在Rom中的,为什么不包含ZI段呢,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。
MCU执行过程是先将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。然后将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中。ROM中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含变量的代码。
堆栈区分析
堆栈解释
(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。
(2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表。
(3)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统自动释放。
(4)文字常量区:常量字符串就是存放在这里的。
(5)程序代码区:存放函数体的二进制代码
例如:
堆和栈的区别
1.stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。
2.stack的空间有限,heap是很大的自由存储区(heap虽然有很大的存储区,但是这个存储区并不是无限大的,在stm32中,heap区的最大值由SRAM区决定,而SRAM区的大小可以参考具体的数据手册)。
3.程序在编译期和函数分配内存都是在栈上进行,且程序运行中函数调用时参数的传递也是在栈上进行。
4.堆和栈空间分配
栈:向低地址扩展(向下增长)
堆:向高地址扩展(向上增长)
显然如果依次定义变量,先定义的栈变量的内存地址比后定义的栈变量的内存地址要大先定义的堆变量的内存地址比后定义的堆变量的内存地址要小。
5.堆和栈变量
栈:临时变量,退出该作用域就会自动释放
堆:malloc变量,通过free函数释放
另外:堆栈溢出,编译不会提示,需要注意。
STM32的分区
STM32的分区从0x2000 0000(0x2000 0000是SRAM的起始地址,由此可知,堆栈等都是在RAM中的)开始。静态区,堆,栈。所有的全局变量,包括静态变量之类的,全部存储在静态存储区。 紧跟静态存储区之后的,是堆区(如没用到malloc,则没有该区),之后是栈区,栈在程序中存储局部变量。
具体可以查看启动文件startup_stm32f428xx.s
这里定义了堆栈各自大小,堆:512bytes 栈:2k; 所以栈区大小有限制,我们在局部变量中不要定义大数组否则容易溢出。
STM32的内存
内存概述
可以双击Project侧边栏的工程,会弹出.map文件,在这个里面,我们就可以清楚的知道这些内存到底是怎么来的了.在这个test.map最后,Image 部分如图
通过这个文件,我们就可以分析整个内存,是怎么被占用的,具体到每个文件,占用比例。
堆heap和stack栈是嵌入式系统的RAM内存分配的基础。设置正确的堆栈大小对于系统的稳定性和可靠性非常重要。堆和栈的空间必须由程序员静态的分配,但计算堆heap和栈stack的空间大小却不是一件简单的事情,即便是对于最小的嵌入式系统。低估栈的使用对带来实时运行中难以预料的错误,并且很难调试。而而高估栈stack的空间则会浪费内存空间。堆Heap的溢出也会对系统行为带来严重的影响,同样难以调试。