在Arduino世界中,有一种常用的技术,您可以使用PROGMEM宏来将字符串和其他类似的数据保存在闪存中,而不是SRAM,以保持较低的内存使用率,同时牺牲一些性能- https://www.arduino.cc/reference/en/language/variables/utilities/progmem/。
基本上,没有将这些存储在SRAM中,而是对一个闪存地址的引用,其中字符串是动态存储和加载的,以便保存RAM。
但我不明白为什么MCU编译器会将函数中的所有字符串(包括本地字符串)放入堆内存中,并将它们始终保存在堆内存中。我也不明白编译器怎么能“在RAM中存储任何东西而不是闪存”-- RAM是不稳定的,所以编译器很难在每次重置时将任何东西“存储”在其中。这些字符串仍然必须存在于存储在闪存上的程序映像中,那么为什么每次启动MCU时它都会将它们从闪存复制到RAM?我在想,也许整个程序映像必须加载到RAM中才能执行,但这是没有意义的,因为这些芯片使用的是哈佛架构,程序已经从FLASH中执行(而且这些芯片中的大部分都有比RAM大得多的闪存,因此整个图像永远不会被放入RAM中)。
虽然我知道如何使用防止这种行为的解决办法,但我不明白为什么这种行为首先存在。有人能把它弄清楚吗?默认情况下,为什么在程序启动时将所有字符串加载到堆中?这是因为性能原因吗?
发布于 2022-09-14 15:05:12
AVR体系结构与许多其他常见体系结构不同,因为代码和数据存在于完全不同的内存空间中(尽管程序内存可以作为数据访问,如您链接到的PROGMEM文档页面中所示)。这是一种改良的哈佛架构。
您可能使用的大多数其他体系结构都是在相同的内存空间中存在的,因为有代码和数据存在于用户面前。虽然这通常也是通过修改过的哈佛体系结构来完成的,但是他们把自己呈现给用户的是一个von架构,具有统一的代码和数据存储空间。
在AVR上,为了使初始化的全局或static数据可用作内存中的任何其他数据,程序启动代码的一部分将初始化数据从程序内存复制到内存中。这通常用于使用名称为.data或.rodata的程序段,这取决于所讨论的变量是否为const。
注意,与您在问题中所说的相反,这些数据不是复制到堆中的,而是存储在程序链接过程中选择的RAM的某个部分中。
使用PROGMEM和相关函数,您可以直接访问存储在AVR设备的闪存中的数据。这个常量数据被放置在一个段中,在启动时不会复制到RAM中,比如.progmem.data,因此内存中没有为它保留的空间。
ESP8266和ESP32家族的一些成员使用的Xtensa体系结构的情况完全不同。与您在问题中的陈述相反,我不认为默认情况下static或全局const对象被复制到内存中,只有那些可以修改的对象( .data段将作为初始化复制到内存中,而.rodata段不会被复制)。
https://stackoverflow.com/questions/73718460
复制相似问题