【发布时间】:2020-05-12 19:06:51
【问题描述】:
我不明白编译器是如何估算 RAM 使用量的。我制作了以下 MCVE。
编译后(Arduino nano ATMEGA328P, new bootloader),Arduino编译器显示的RAM使用错误。我比较了创建DataContainer 结构实例的两种方式,通过使用new(运行时,堆?是正确的名称)创建一个指针数组和调用构造函数,以及仅创建一个结构数组(编译时间?)。
#include <Arduino.h>
struct DataContainer {
int values[100] = {0}; // init to zeros
void FillRandom() {
for (int k = 0; k < 100; k++)
values[k] = random(0, 200);
}
};
class ExampleClass
{
public:
DataContainer *data[20]; // Heap, runtime?
// DataContainer data[20]; // or compile time
ExampleClass() {
for (int k = 0; k < 20; k++)
data[k] = new DataContainer(); // not necessary when using: DataContainer data[20]
}
};
// declare class
ExampleClass EC;
void setup() {
// call constructor
EC = ExampleClass();
EC.data[1]->FillRandom(); // for run time
// EC.data[1].FillRandom(); // for compile time
}
如果我比较编译器显示的 RAM 使用情况,我会看到以下内容。
案例1,使用DataContainer *data[20];
RAM: [ ] 3.1% (used 63 bytes from 2048 bytes)
Flash: [= ] 5.8% (used 1782 bytes from 30720 bytes)
案例2,使用DataContainer data[20];
RAM: [==========] 195.9% (used 4013 bytes from 2048 bytes)
Flash: [ ] 3.9% (used 1194 bytes from 30720 bytes)
(我知道这不适合 Arduino,仅作为示例)。
有没有办法估计 RAM 使用情况?
【问题讨论】:
-
编译器并不真正知道您在运行时动态分配了多少内存,它需要编译器通常需要的更多分析。它所能做的就是使用它拥有的信息来估计,即您在堆栈上创建一个对象,其大小为
20 * 4字节。我不知道它是如何计算“RAM”的,但是在运行您的程序时,堆栈上将占用至少 80 字节的内存(加上返回地址等的少量额外内存)。如果您创建一个 objects 数组,那么在堆栈上至少有20 * (100 * 4),即 8000 字节。 -
至于差异,也许您的 Arduino 模型(您没有告诉我们)使用的是 16 位 CPU,其中指针的
sizeof以及int是每个 16 位(2 个字节)?那么它会更有意义。 -
在小型嵌入式系统上,如 Arduino Nano,动态内存分配几乎总是会产生很多开销。您不仅需要内存用于对象本身,还需要内存用于指向对象的指针,以及内存分配器内部的内务管理和元数据。由于您只有 2KiB 的 RAM,因此您必须对变量和对象非常保守,并且必须从头开始基于此限制进行设计。
-
我在为内存受限的设备编写操作系统方面拥有丰富的经验,我强烈建议您使用只有 2048 字节 RAM 的情况下使用 C 编程,而不是 C++。
-
@MichaëlRoy:是的。我强烈建议他们不要这样做。