最近在做代码的内存优化,故记录此笔记及心得。(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修饰变量但不初始化”这个操作,这显然是不合理的。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐