如何在Arduino C代码中发现内存溢出错误?


10

在将代码上传到Arduino之后,有几次我在串行监视器上有一些可疑的输出:例如,空白的永恒输出或突然截断字符串或​​混乱的字符串。

因为Arduino IDE中没有编译错误或警告,所以我认为Arduino已损坏,但是经过一些测试,我发现Arduino IDE编译器无法捕获所有类型的错误-尤其是在为数组结构循环分配变量时。这似乎在短时间内使Arduino崩溃。

如何发现Arduino IDE未显示的错误?

Answers:


10

MemoryFree库可以帮助你找到内存使用的风险。

例:

#include <MemoryFree.h>

// On Arduino Duemilanove with ATmega328:
//
// Reported free memory with str commented out:
// 1824 bytes
//
// Reported free memory with str and Serial.println(str) uncommented:
// 1810
//
// Difference: 14 bytes (13 ascii chars + null terminator)

// 14-bytes string
//char str[] = "Hello, world!";


void setup() {
    Serial.begin(115200);
}


void loop() {
    //Serial.println(str);

    Serial.print("freeMemory()=");
    Serial.println(freeMemory());

    delay(1000);
}

我不确定MemoryFree是否占栈指针。如果您的堆栈指针与堆指针冲突,则可能会遇到分段错误。


7

RAM耗尽的最常见原因是使用String对象或使用许多恒定字符数组(c样式字符串)。

不幸的是,IDE 1.0.4包含了对malloc的修复,该修复困扰了String对象很长时间了。

为了减少常量字符字符串浪费的RAM,例如:

Serial.print("Hello World");  // This consumes RAM!

您可以使用F()宏。此宏将强制字符数组保留在PROGMEM中。使用阵列时,仅消耗一个字节的内存。

Serial.print(F("Hello World"));  // Keeps the character-array in PROGMEM

请记住,在运行时不能更改存储在PROGMEM中的字符串。

就发现而言,在没有调试器或内存控制器的情况下,您必须使用老式的侦探技术来查找问题发生的位置。


1
感谢您的帮助!真的没有IDE支持的内存调试器吗?
powtac

1
这是一个古老的问题,但是,是的,有适当的调试器可用于atmel ATmega MCU。没有arduinos调试器,因为arduino工具链和“ IDE”基本上是玩具。
康纳·沃尔夫

1
实际上,您对F()的提示为我们节省了数百字节的RAM!
powtac

1
将F()与包含的字符串一起使用时,出现编译错误//。:-(
powtac 2014年

我在Arduino 1.5.7上遇到此编译错误...
powtac 2014年

3

看起来您在这里谈论的是运行时错误(内存泄漏/段错误类型)。

在已编写的代码中,没有任何方法可以发现此类错误(除非您非常仔细地梳理代码)。但是,很容易防止在编写代码时发生这些情况。在编写循环或递归调用时要非常小心;问自己“这会失控吗?”。如果看起来这是使其“失控”的范围,请编写代码以防止这种情况。

关于段故障-只需检查数组索引的边界值,就可以了。如果您使用的是指针,请谨慎使用指针算法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.