内存碎片是否会导致Arduino耗尽RAM,即使程序使用的RAM不到一半



我正在使用Arduino Nano every,它有6kB的RAM,我相信我可以编写程序,使用不到一半的RAM。我的程序在void循环中有一些变量,其中一个是10个字符的字符串,每秒覆盖10次。存在其他变量,包括<每秒也被重写10次的函数中的10个字符串(。

当然,如果我使用的RAM不到一半,那么无论RAM变得多么碎片化,当对变量执行某些操作时,内存分配器总是会发现足够大的漏洞来容纳新数据

我已经听说,弦是反对阿都诺。这确实让我感到惊讶,因为char数组完全能够引起内存碎片。我不想把我的字符串换成char数组,因为我使用serial.readstring((从串行端口读取整个字符串。要使用char,我需要使用serial.read((,它只接收1个字符,这使过程更加繁琐。

我不想把字符串换成char数组,因为我使用的是serial.readstring((

Serial.readString()返回一个String对象,该对象的内部缓冲区(来自源,因为它没有文档记录(是动态分配的(如果大小增加,则会重新分配(。每个分配将是8字节对齐的并且包括可能也是8字节的块报头;开销";用于小分配的空间(即所分配的存储器的用户使用但不可用的空间(可能与所分配的用户存储器成比例地相当大。

现在您必须意识到,动态内存分配来自,并且并非所有6Kb都将分配给堆。首先,链接器将分配所有静态数据对象,然后是堆,剩下的将是可用的堆栈。在6Kb的部分上,几乎没有任何空间来放置大小有用的堆。

更普遍地说,在嵌入式系统中使用系统堆通常是一个坏主意——在这种情况下,由于内存不足是一个问题,但在所有情况下,缺乏实时确定性行为和在运行时耗尽时的错误处理都是问题。

请参阅https://docs.arduino.cc/learn/programming/memory-guide有关可用于确定板上可用堆空间的代码的信息,以及有关Arduino上内存使用情况的其他信息。

碎片可能不是问题,而不是简单的内存耗尽。只有当您重复分配和释放块时,才会发生碎片化——如果您分配而从不释放,则不会发生碎片化。在String对象的情况下,当它被销毁时,它的内存就会被释放——对于动态创建的对象来说是删除的,或者对于本地对象来说是超出范围的。静态分配的String对象不会被销毁。因为String内部使用realloc(),所以如果字符串长度增加,它可以释放内存——可能会导致碎片,但可以通过使用String.reserve()预分配足够的容量来避免这种情况。

然而,这个问题是一个很容易解决的问题;"笨重"-至少在你写了一个合适的函数(或者从这里复制粘贴它(之后不会。例如:

char* SerialReadString( Serial& port, char* buffer, size_t length, int timeout )
{
int start = millis() ;
size_t ci = 0u ;
while( ci < length - 1 && 
(port.available() != 0 || millis() - start <= timeout) )
{
int ch = port.read() ;
if( ch > 0 )
{
buffer[ci] = ch ;
buffer[ci+1] = 0 ;
}
}
return buffer ;
}

如果不使用动态内存,就不会得到内存碎片。动态内存是在使用malloc()和friends或new关键字时分配的,这在Arduino程序中并不常见。您提到的所有内容要么在固定大小的堆栈上,要么在程序生命周期内分配一次。

最新更新