浅谈单片机内存管理(FLASH、ROM、RAM)
本文探讨了嵌入式开发中的内存优化问题。通过实验分析发现:1)FLASH存储程序代码和常量,RAM存储变量和堆栈;2)const修饰的未初始化变量会被存储在RAM的bss段而非FLASH,且实际上可被修改;3)最终建议避免使用const修饰但不初始化变量的做法,因其违背常量特性且可能导致内存使用不合理。实验使用VS2022+GD32F3平台,通过map文件和memcpy操作验证存储位置和读写属性。
最近在做代码的内存优化,故记录此笔记及心得。(VS2022 Visual GDB + GD32F3)
1、FLASH、ROM、和RAM是怎样的关系
比如下图中,为什么FLASH的子项有一个ROM?
首先,在这里ROM和RAM是一个逻辑概念,分别是只读存储器区域和随机存取存储器区域,而FLASH是存储介质,是物理上的非易失存储器,看得见摸得着。
它出现在 “FLASH” 目录下,这明确地表示这个执行区域映射到了物理的 FLASH 存储器空间。所以,ER_IROM1就是ROM 内容在 FLASH 上的存储区域。
2、代码段、数据段存储在哪
先说结论,FLASH存储只读数据,RAM存储可读写数据,所以分区如下
FLASH存储:
·code段(程序代码)
·constdata段(常量const)
RAM存储:
·data段(初始化的全局变量、静态变量)
·bss段(未初始化的全局变量、静态变量)
·堆(动态申请)
·栈(局部变量及其它)
(看完结论先别急着走,重头戏在后边呢 /* 手动狗头 */)
3、结论的验证
直接添加一个全局变量gMemoryTest不初始化,查看map,可以看到存储在bss段,如下图
加上初始化,可以看到gMemoryTest存储到了data段,如下图
有趣的是加上初始化后IDE认为gMemoryTest不存储在RAM了,标出RAM减小了800字节,但RAM使用到了0x20015757依旧没改变。(应该是IDE的bug)
同样的,继续加上const修饰后,可以看到FLASH占用增加了800字节,且存储到了FLASH的constdata段,如下图
到这里我突发奇想,要是在此基础上,不给它初始化,会怎么样?
于是我仅声明gMemoryTest,不再显式的初始化它。
它居然存储到bss段了!!!
4、有趣的const
为什么会存储到bss段呢?难道它不算是常量了?
于是我打算验证一下它的属性:(直接赋值)
很显然,编译报错了,必须是可修改的左值!
那应该是具备const只读属性的呀,那为什么存储到了bss段呢?
不对!我突然意识到确认属性不应该依赖编译器,编译器只会呆呆的看这个数据前面有没有一个“const”修饰,应该实实在在的去尝试改变gMemoryTest,才能确认它的读写属性。
于是我想到了memcpy:
首先我尝试用memcpy修改正常初始化的const常量,通过监视数组,发现确实无法修改。
于是我用同样的方式修改未初始化的const,居然修改成功了!!!
可以看到它确实被修改成了我指定的数据。它不具备只读属性!
到这儿,也侧面印证了为什么它存储在了RAM的bss段而不是FLASH的constdata段。
结论:
const修饰变量但不初始化,在语法上不允许修改它,但实际上它是可读写、可修改的。
最后,在代码上一定要避免“const修饰变量但不初始化”这个操作,这显然是不合理的。
更多推荐
所有评论(0)