『7x24小时有问必答』

对于使用RTOS进行项目开发的朋友可能会有这样的疑惑,我创建的任务到底需要多大的堆栈空间才够呢?

其实,除了使用RTOS开发,就是使用裸机进行开发的朋友同样也会遇到类似的问题,有些地方需要很大的堆栈,对系统堆栈的分配就有必要知道其大小,如果分配不充分,很有可能导致内存溢出。

之前就有小伙伴问:我的代码经常运行到“HardFault_Handler”、 “MemManage_Handler”异常中断里面去了,是什么原因导致的呢?

当我们遇到内存溢出现象时,查看map文件,很快就能找到那些代码占用了多少空间

还有很多小伙伴问:我代码、内存占用的资源如何查看呢?当你们了解了map文件里面的内容,以上问题就一目了然了。

输出map配置
在工程中,默认是输出了map文件,如果没有输出,需要如下配置:

当按照上面配置勾选了“生产map”文件,就可以看到如下情况:

下面才是重点,就让我给大家详细讲述一下IAR中map文件的重要内容。map文件主要分为六大块,详情见下面章节。
Ⅰ、MAIN INIF
Ⅱ、RUNTIME MODEL ATTRIBUTES
Ⅲ、PLACEMENT SUMMARY
Ⅳ、INIT TABLE
Ⅴ、MODULE SUMMARY
Ⅵ、ENTRY LIST

MAIN INIF主要信息

这段信息比较简单,关于map文件的主要信息。包含:IAR版本、日期、输出文件路径、map文件路径等。

RUNTIME MODEL ATTRIBUTES

RUNTIME MODEL ATTRIBUTES:运行时MODEL属性。这部分显示相关属性等信息,可以不用深入理解。

PLACEMENT SUMMARY

PLACEMENT SUMMARY:概述位置,即各Section(段)存储的位置。

1.总体概述
"A0":   place at 0x08000000 { ro section .intvec };
"P1":   place in [from 0x08000000 to 0x0801ffff] { ro };
"P2":   place in [from 0x20000000 to 0x20004fff] { rw, block CSTACK, block HEAP };
意思是:
"A0"段位于0x08000000,类型为intvec(初始化向量);
"P1"段位于0x08000000 至 0x0801ffff区域,类型为ro;
"P2"段位于0x20000000 至0x20004fff区域,类型包含:rw, block CSTACK, block HEAP;

2.详细说明
Section   Kind      Address    Size    Object
段               类型            地址       大小      目标位置

"A0":                                       0xec
   .intvec    ro code   0x08000000   0xec   startup_stm32f10x_md.o [1]
                          - 0x080000ec    0xec
意思是:
"A0"段总共大小为0xec;
其中“.intvec”段类型为ro,地址0x08000000,大小0xec,位于
                                                  startup_stm32f10x_md文件;
"A0"段结束地址为0x080000ec,总共大小0xec。

提示:
段与类型一般有对应关系
        Section             Kind
"A1":  
        .intvec               ro code(ro代码)

"P1":
        .text                  ro code(ro代码)
        .rodata               const (常量)
        CODE                ro code(ro代码)
        .iar.init_table       const(常量)
        Initializer bytes    ro data(ro数据)

"P2":
        .data                inited(已初始化数据)
        .bss                  zero(未初始化数据 零)

INIT TABLE

INIT TABLE:初始化表,类似于上面第三部分内容,这里是针对RAM存储地址。

MODULE SUMMARY

MODULE SUMMARY:概述模块,主要概述文件于库(模块)所占ro代码大小、rw数据大小。

ENTRY LIST

ENTRY LIST:入口列表,包含函数、变量等入口地址。

其中Entry(入口)主要包含两大类:函数和变量。
函数:全局函数、静态函数
变量:全局变量、(文件内)静态变量、(函数内)静态变量

入口                     地址            大小    类型       目标
Entry                     Address       Size      Type       Object

main                     0x08000317   0x5e    Code   Gb   main.o [1]
SetSysClock             0x08000141   0x8      Code   Lc   system_stm32f10x.o
gVar                      0x20000000   0x4      Data   Gb   main.o [1]
sVar_E                   0x20000004   0x4      Data   Lc   main.o [1]
main::sVar_I            0x20000008   0x4      Data   Lc   main.o [1]

从上面列表的差异可以看到出来主要包含五类:
1.“全局”函数
入口:main,为全局函数接口;
地址:0x08000317,代表存储在FLASH
大小:0x5e,该入口函数大小为0x5e;
类型:Code Gb,其中code说明为代码,Gb说明为“全局的”函数(Global);
目标:main.o,该入口函数位于main.c文件下面。
  
2.“静态”函数
静态函数也就是在函数前加static.
SetSysClock位于system_stm32f10x.c文件下,可以看到前面加了“static”。
类型为Code Lc,即静态(局部Local)函数;

3.全局变量
全局变量也叫“全局数据”,因为它的类型为“Data Gb”。
从地址0x20000000可以看得出,它是位于RAM区域,也就是内存中。
提示:只有全局和静态的变量才会在编译之后决定在RAM中的地址,定义在函数体里面的局部变量只有在程序运行时才会分配地址,也就是说局部变量位于堆栈中)。

4.(文件内)静态变量
使用static关键字定义的变量,只有在当前文件内使用,所以它属于静态(“局部”Local)变量。

5.(函数内)静态变量
它和“(文件内)静态变量”类似,属于静态变量,只是它定义在函数体内的。
从入口main::sVar_I”可以看得出,变量sVar_I定义在main函数体内。

map文件的最后有如下一段信息
[1] = C:\Users\Administer\Desktop\Demo\Debug\Obj
[2] = command line
[3] = dl7M_tln.a
[4] = m7M_tls.a
[5] = rt7M_tl.a
[6] = shb_l.a

   130 157 bytes of readonly   code memory
     18 736 bytes of readonly   data memory
   121 508 bytes of readwrite data memory

Errors: none
Warnings: none

相信大家都会明白,信息就是所有代码、内存块汇总的。而这条信息也会在编译窗口中显示出来。

---

微信搜索“EmbeddDeveloper” 或者扫描下面二维码、关注,在我的底部菜单查看更多精彩内容!

长按识别二维码 关注

如果对你们有用就点个赞 点下广告支持下吧!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码