做嵌入式工程师很多年了,有的同事经常ram和flash傻傻分布清楚,只知道ram里有堆栈,不知道RO-data、RW-data和.bss段.data段有什么联系,这里我做了一个系统的归纳,仅针对微处理器的flash以及ram的内存分配进行讲解;
在讲解之前先说一下哈佛结构和冯·诺依曼架构
为什么开题要讲一下这连个架构呢,因为不同的架构决定着实际ram和flash中内容分配有不同策略
(英语:Harvard architecture)是一种将程序指令储存和数据储存分开的存储器结构。中央处理器首先到程序指令储存器中读取程序指令内容,解码后得到数据地址,再到相应的数据储存器中读取数据,并进行下一步的操作(通常是执行)。程序指令储存和数据储存分开,数据和指令的储存可以同时进行,可以使指令和数据有不同的数据宽度;
归纳一下所谓的哈弗架构其实就是将指令存储与数据存储分开,大部分的微处理器都是这种架构,程序放在flash中,而数据放在ram中,共用两条不同的总线,这种架构的优势是程序运行迅速,程序和数据加载读取分别在不同的总线上并行处理,对于小flash需求的场景非常适合;
(von Neumann architecture),也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的电脑设计概念结构。本词描述的是一种实作通用图灵机的计算装置,以及一种相对于平行计算的序列式结构参考模型(referential model)。
本结构隐约指导了将储存装置与中央处理器分开的概念,因此依本结构设计出的计算机又称储存程式型电脑。
概括一下这个架构的特点,就是指令存储与数据存储是在一起的,X86、大部分soc都是这种架构,这就是为什么他们都是需要先从存储器中读取程序代码,并将程序代码加载到内存中再去运行的原因
上面我们已经阐述了微处理器的架构特点,那么我们考虑一下在微处理器中ram主要存放的东西是什么?---数据
数据包括什么呢?全局变量,局部变量、静态变量、常量,其中除了常量都是存放在ram中;
ram的区域定义从上到下依次是:
栈(stack)
堆(heap)
未初始化全局区(.bss)
初始化全局区(.data)
.bss段都包含那些内容呢?零数据段,存放未初始化的全局变量及局部静态变量,或者是初始化为0的全局变量以及局部静态变量;
.data段包含的内容呢?初始化数据段,存放初始化的全局变量及局部静态变量;
那么怎么看查看程序运行中内存的使用情况呢?从分析可知内存的变化主要是因为堆、栈,将固件下载到微处理器的那一刻起,.bss以及.data的大小已经基本确定,只要评估甚于堆与栈的大小就能评估当前内存的使用情况;
针对MDK编译出的hex或者bin文件,IDE自主定义了几种数据段来描述flash存储内容我先介绍几个名词;
ZI-data: 零数据段
RW-data:可读写需要初始话数据段
RO-data:只读数据段;
text:代码段
所以编译好的bin文件或者是hex文件著有就是由上述的四个段构成,一般编译器都会生成.map文件可以查看每个数据段在镜像文件中的相对地址;
对于flash以及ram而言最大的区别就是数据易失性不同,所以由于这种特性可以将固件中一部分掉电可失去的数据放到ram中,对于flash而言flash真正存储的内容如下
需要初始化的数据(RW-data)
只读常量(RO-data)
代码(code)
flash size = code_size + RO-data_size + RW-data_size;
大家会发现其中并没有ZI-data数据段,flash一般不存储ZI-data数据段,而是保存一些数据段地址以及数据段大小的信息;
前面已经详细的概述了flash以及ram中的具体组成内容,这里顺便说一下程序运行时是如何完ram内容分配的,
程序上电-》code、RO-data不搬运-》将 RW 段中的 RW-data 搬运到 RAM 的.data区-》 据编译器给出的 ZI 地址和大小分配出 ZI 段,并将这块 RAM 区域清零为.bss区-》剩下的空间为堆heap、栈stack
总结一下一定不要将镜像的存储数据段与ram的数据区概念混淆;