关于Keil、IAR编译后数据内存的分析

写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

一、Keil C51编译器

1、首先,在Options ----> Target ----> Memory Model 里可以设置变量分配的空间,如图示:
在这里插入图片描述

  • Small:变量默认分配到内部存储空间中,通过普通的MOV指令寻址,只用低于2K的程序空间。
  • Compact:变量默认分配到外部页存储空间中,单个函数的代码量不能超过2K,整个程序可以使用64K的程序空间,通过MOVX, @Ri之类指令寻址,在不切换页的前提下,最大支持256字节外部扩展RAM。
  • Large:变量默认分配到外部存储空间中,通过MOVX, @DPTR之类指令寻址,最大支持64kB外部扩展RAM(实际上配合硬件设计以及软件调整,还可以支持更大的扩展空间)。

2、程序中,如果在变量声明时未声明变量的存储器类型,则该变量的存储器类型,由程序的存储模式来决定,也就是说编译器会根据我们在上面 Memory Model 里所选的模式默认储存在那个区域。

  • 小模式(Small model):默认data区
  • 紧凑模式(Compact model):默认pdata区
  • 大模式(Large model):默认xdata区

3、各分配区域的理解
data:直接寻址的片内RAM区低128B(00H~7FH) , 可以用acc直接读写的,速度最快,生成的代码也最小。

bdata:片内RAM的可位寻址区(20H~2FH),允许字节和位混合访问

idata:单片机间接访问的片内RAM区,允许访问全部片内RAM(前面0x00-0xff的256个RAM),其中前128和data的128完全相同,只是因为访问的方式不同。idata是用类似C中的指针方式访问的。汇编中的语句为:mox ACC,@Rx.(不重要的补充:c中idata做指针式的访问效果很好)

pdata:Ri间接访问的片外RAM的低256B(00H~FFH)

xdata:外部扩展RAM,用DPTR间接访问片外RAM,允许访问全部64KB片外RAM(0000H~FFFFH)

code:单片机的64KB程序存储区ROM,即代码域,它指的是编译器生成的机器指令,这些内容被存储到ROM区,写入后就不能再更改,一般当你定义数组不用更改时可以加上这个关键词,对应的data是存入RAM的意思

4、如下图所示,编译出来的 “ Program Size: data=10.3 xdata=588 code=8732 ” ,对应的数值就是该区域所占用的空间大小在这里插入图片描述

二、Keil MDK-Arm编译器

1、同样是 Keil编译器,MDK相对于 C51,在 Options ----> Target里并没有Memory Model的设置,用的比较多的是下面的这个配置
关于Keil、IAR编译后数据内存的分析_第1张图片
这个是程序存储在片内、片外的地址设置(一般下载程序都是下载到片内FLASH),我们也不用怎么去更改它;只有在项目做大了,或有特殊要求时,片内不够使用了才将程序存储在片外
2、数据类型的理解
Code:即代码域,它指的是编译器生成的机器指令,这些内容被存储到ROM区。

RO-data:Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在ROM区,因而程序不能修改其内容。例如C语言中const关键字定义的变量就是典型的RO-data。

RW-data:Read Write data,即可读写数据域,它指初始化为 “ 非0值 ” 的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。例如C语言中使用定义的全局变量,且定义时赋予“非0值”给该变量进行初始化。

ZI-data:Zero Initialie data,即0初始化数据,它指初始化为“0值”的可读写数据域,它与RW-data的区别是程序刚运行时这些数据初始值全都为0,而后续运行过程与RW-data的性质一样,它们也常驻在RAM区,因而应用程序可以更改其内容。例如C语言中使用定义的全局变量,且定义时赋予“0值”给该变量进行初始化(若定义该变量时没有赋予初始值,编译器会把它当ZI-data来对待,初始化为0);

ZI-data的栈空间(Stack)及堆空间(Heap):在C语言中,函数内部定义的局部变量属于栈空间,进入函数的时候从向栈空间申请内存给局部变量,退出时释放局部变量,归还内存空间。而使用malloc动态分配的变量属于堆空间。在程序中的栈空间和堆空间都是属于ZI-data区域的,这些空间都会被初始值化为0值。编译器给出的ZI-data占用的空间值中包含了堆栈的大小(经实际测试,若程序中完全没有使用malloc动态申请堆空间,编译器会优化,不把堆空间计算在内)。

三、IAR For STM8(EWSTM8)编译器

1、IAR查看编译后内存大小不会像 Keil那样在编译完直接在 Build窗口显示出来,需要我们去 Options for node里面设置一下,具体操作 Options for node ----> Linker ----> List ----> 把Generate linker map file打勾;如图:
关于Keil、IAR编译后数据内存的分析_第2张图片
2、根据上面的操作,设置完后编译,在工作空间窗口 Output文件下可以找到 .map的文件,点击打开,在末尾可以看到目标代码占用的空间大小,如图所示:
关于Keil、IAR编译后数据内存的分析_第3张图片

  • Flash = readonly code memory + readonly data memory
  • RAM = readwrite data memory

括号内的,表示内存的绝对使用量,对应你设的全局变量大小;对应生成的 bin文件大小 = 5590 + 168

四、优化

一般每个编译器都有优化选项,对应选择不同的优化等级,你会发现同样的代码,编译出来的占用内存大小是不同的,再细心一点同样可以发现存放在 RAM区域的内存大小是不会怎么变化的,变化较大的是存在 flash区域的内存,所以一般的不会定义全局变量(除非真的要用到),并且全局变量处理起来比较麻烦;另外,开了优化后,如果进入调试,可能有些地方会放不了小红点(打断点),因为编译器根据你所选的优化等级,把对应的代码给优化了。

你可能感兴趣的:(软件相关)