简体   繁体   English

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

[英]Can memory fragmentation cause an Arduino to run out of RAM even if the program uses less than half of the RAM?

I am using the Arduino Nano every which has 6kB RAM and am confident that I can write my program to use less than half of the RAM.我正在使用 Arduino Nano,每个都有 6kB RAM,并且我相信我可以编写我的程序来使用不到一半的 RAM。 My program has some variables in the void loop, one of which is a 10 character string, which are overwritten 10 times a second.我的程序在 void 循环中有一些变量,其中一个是 10 个字符的字符串,每秒被覆盖 10 次。 There are additional variables including <10 character strings in functions that are also over written 10 times a second).还有其他变量,包括函数中的 <10 个字符串,每秒也被覆盖 10 次)。

Surely, if I am using less than half of the RAM, then no matter how fragmented the RAM becomes, the memory allocator will always find holes large enough to fit the new data when some operation is performed on a variable?当然,如果我使用的 RAM 不到一半,那么无论 RAM 变得多么碎片化,当对变量执行某些操作时,memory 分配器总是会找到足够大的孔来容纳新数据?

I have already heard that strings are frowned upon on Arduinos.我已经听说 Arduinos 不赞成使用字符串。 It does surprise me since char arrays are perfectly capable of causing memory fragmentation.这确实让我感到惊讶,因为 char arrays 完全能够导致 memory 碎片。 I don't want to swap my strings for char arrays because I am using serial.readstring() to read the entire string from the serial port.我不想将字符串换成 char arrays,因为我正在使用 serial.readstring() 从串口读取整个字符串。 To work with char, I would need to use serial.read() which only receives 1 character, making the process far more cumbersome.要使用 char,我需要使用仅接收 1 个字符的 serial.read(),这使得该过程更加繁琐。

If you aren't using dynamic memory you won't get memory fragmentation.如果您不使用动态 memory,您将不会得到 memory 碎片。 Dynamic memory is allocated when you use malloc() and friends , or the new keyword, not typical in Arduino programs.动态 memory 是在您使用malloc()和朋友new关键字时分配的,这在 Arduino 程序中并不常见。 Everything you mentioned is either on the stack which is a fixed size or allocated once for the life of the program.您提到的所有内容要么在固定大小的堆栈上,要么在程序的生命周期内分配一次。

I don't want to swap my strings for char arrays because I am using serial.readstring()我不想用我的字符串交换 char arrays 因为我正在使用 serial.readstring()

Serial.readString() returns a String object, the internal buffer for which (from the source , because it is not documented) is dynamically allocated (and reallocated if the size increases). Serial.readString Serial.readString()返回一个String object,其内部缓冲区(来自,因为没有记录)是动态分配的(如果大小增加则重新分配)。 Each allocation will be 8 byte aligned and include a block header which might be 8 bytes also, so the "overhead" space (that is space used but not available to the user of the allocated memory) for small allocations may be considerable in proportion to the user memory allocated.每个分配将是 8 字节对齐的,并包括一个块 header 也可能是 8 个字节,因此小分配的“开销”空间(即已使用但对已分配内存的用户不可用的空间)可能与用户 memory 已分配。

Now you have to realise that dynamic memory allocations are from the heap and not all of your 6Kb will be allocated to the heap.现在您必须意识到动态 memory 分配来自,并非所有 6Kb 都将分配给堆。 First the linker will allocate all static data objects, then the heap, and what is left will be the available stack.首先 linker 将分配所有 static 数据对象,然后是堆,剩下的将是可用堆栈。 On a 6Kb part there will hardly be any space for a usefully sized heap.在 6Kb 的部分上,几乎没有任何空间可容纳有用大小的堆。

More generally using the system heap in embedded systems is a generally a bad idea - in this case through lack of memory is an issue, but in all cases lack of real-time deterministic behaviour and error handling in the event of exhaustion at run-time are issues.更普遍地说,在嵌入式系统中使用系统堆通常是一个坏主意 - 在这种情况下,由于缺少 memory 是一个问题,但在所有情况下,在运行时耗尽的情况下都缺乏实时确定性行为和错误处理是问题。

See https://docs.arduino.cc/learn/programming/memory-guide for information on code that can be used to determine the available heap space on your board and other information about memory usage on Arduino. See https://docs.arduino.cc/learn/programming/memory-guide for information on code that can be used to determine the available heap space on your board and other information about memory usage on Arduino.

Fragmentation may not be the issue rather then simple memory exhaustion.碎片可能不是问题,而是简单的 memory 耗尽。 Fragmentation only occurs if you are repeatedly allocating and releasing blocks - if you allocate and never release, fragmentation will not occur.仅当您重复分配和释放块时才会发生碎片 - 如果您分配并且从不释放,则不会发生碎片。 In the case of a String object, it's memory is released when it is destroyed - deleted for a dynamically created object or goes out of scope for a local object. In the case of a String object, it's memory is released when it is destroyed - deleted for a dynamically created object or goes out of scope for a local object. String objects that are statically allocated will not be destroyed.静态分配的String对象不会被销毁。 Because String internally uses realloc() it can release memory if the string length increases - that can cause fragmentation perhaps, but that can be avoided by pre-allocationg sufficient capacity with String.reserve() .因为String在内部使用realloc()它可以在字符串长度增加时释放 memory - 这可能会导致碎片,但是可以通过使用String.reserve()预先分配足够的容量来避免这种情况。

The problem however is an easy one to solve and not at all "cumbersome" - at least not after you have written a suitable function (or copy and pasted it from here even).然而,这个问题很容易解决,而且一点也不“麻烦”——至少在你写了一个合适的 function 之后(或者甚至从这里复制并粘贴它)。 eg:例如:

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 ;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM