arduino简单string入门——使用 StringReserveCheck查找并消除漏洞
要检测何时未预留足够的空间,可以使用StringReserveCheck 类。下载StringReserveCheck.zip 文件并使用 IDE Sketch → Include Library → Add .ZIP library... 安装它。
然后,您可以添加 StringReserveCheck 对象来跟踪每个长寿命字符串。StringReserveCheck 的使用方法如下:-
在要检查的每个字符串之后立即分配一个 StringReserveCheck 对象。例如对于全局字符串
#include <StringReserveCheck.h>
String string1;
StringReserveCheck string1Check;
这确保了 String 和 StringReserveCheck 对象具有相同的范围和生命周期。
在 setup() 中,在为字符串保留空间之后,立即调用其 StringReserveCheck 对象上的init() 来捕获初始状态。init () 还允许您指定在何处写入 checkReserve 消息。例如
void setup() { . . . string1.reserve(32); string1Check.init(string1); // checkReserve( ) will not print any msgs, you need to check its return value string2.reserve(32); string2Check.init(string2, Serial); // init( ) will print a msg if memory is low and checkReserve( ) will print a msg if (!string3.reserve(32)) { // check the last largest reserve while (1) { // stop here and print repeating msg Serial.println(F("Strings out-of-memory")); delay(3000); // repeat msg every 3 sec } } if (!string3Check.init(string3, Serial)) { // check return for low memory Serial.println(F("Memory Low after reserves()")); } . . . }
如果内存不足,stringCheck.init(string, Serial); 将打印一条警告消息并返回 false。stringCheck.init (string); (没有 Serial 参数) 不会打印任何消息,因此您需要检查返回值。
然后,当你想检查储备时,你可以使用stringCheck.checkReserve() 。例如
void loop() { float temp = 27.35; printDegC(temp, string2); Serial.println(string2); string1Check.checkReserve(); // init(string1,Serial); was specified so msg printed if (!string2Check.checkReserve()) { // check return, init(string2,Serial); was specified so msg also printed Serial.print(F("string2 reserve too small. Current length():")); Serial.println(string2.length()); } if (!string3Check.checkReserve()) { // init(string3); // no output specified, check return Serial.print(F("string3 reserve too small. Current length():")); Serial.println(string3.length()); } Serial.println(); }
MemFrag_ex3.ino 已添加这些StringReserveCheck。MemFrag_ex3.ino的输出 为
内存碎片示例 3 这是锅炉房的温度 27.4 摄氏度 !!reserve() 对字符串 'This is th...' 来说不够大 当前长度:51 string2 保留太小。当前长度():51 reserve() 对字符串 'string3 in...' 来说足够大 当前长度:21
此输出清楚地表明 string2 的保留需要增加,并且当前长度提示了新的保留应该是多少。string3 的保留正常。打印该消息是因为在 string3Check.init(string3,Serial) 语句中将 Serial 设置为输出。没有为 string1 打印任何消息,因为string1Check.init(string1); 没有指定将消息发送到何处。
摘要:使用StringReserveCheck 类检查初始保留是否足够大以用于应用程序。如果 checkReserve() 返回 true,则表示此字符串没有因重新分配而产生碎片。
当 UNO 或 Mega2560 耗尽堆内存时会发生什么情况
当堆栈与堆发生冲突时,内存不足是致命的。如上面的 SRAM 图所示,每次调用方法时,堆栈都会为方法返回、方法参数和任何方法局部变量使用更多空间。堆栈不会检查堆在哪里,只会占用所需的空间。结果是,当内存耗尽时,堆栈会覆盖现有的堆对象,从而导致内存损坏和程序崩溃。
Arduino UNO 只有 2048 字节的 SRAM,因此很容易在该板上出现内存不足的情况。只需使用“text... ”而不是 F(“text... ”) 即可。但是,当您在 UNO 或 Mega2560 和其他基于 AVR 的板上使用字符串时,由于内置了 128 字节的__malloc_margin ,它们在堆内存不足的情况下非常稳定。堆栈始终至少有那么多空间可用于保持程序运行。
在MemFrag_ex4.ino中,string1 和 string3 的保留大小已针对 UNO 进行了仔细调整,以便几乎所有内存都得到使用。然后,当 sketch 尝试将 string2 从其保留的 32 重新分配为更大的值以处理更长的标题时,它会耗尽内存。
void setup() { . . . Serial.println(F("Memory Fragementation Example 4 - Out Of Memory")); string2.reserve(32); // do reserve in order smallest first string2 string2Check.init(string2, Serial); // init( ) will print a msg if memory is low and checkReserve( ) will print a msg string1.reserve(600); // next largest string1 string1Check.init(string1); // checkReserve( ) will not print any msgs, you need to check its return value if (!string3.reserve(930)) { // do largest last and check its return while (1) { // stop here and print repeating msg Serial.println(F("Strings out-of-memory")); delay(3000); // repeat msg every 3 sec } } if (!string3Check.init(string3, Serial)) { // check return for low memory Serial.println(F("Memory Low after reserves()")); } . . . }
Then when the MemFrag_ex4.ino sketch is run the output is
!! Low memory available, stability problems may occur. Memory Low after reserves() Memory Fragementation Example 4 - Out Of Memory 27.4degC !! reserve() NOT large enough for String '27.4degC' Current len:8 string2 reserve too small. Current length():8 reserve() large enough for String 'string3 in...' Current len:21 27.4degC !! reserve() NOT large enough for String '27.4degC' Current len:8 string2 reserve too small. Current length():8 reserve() large enough for String 'string3 in...' Current len:21
即使 UNO 内存不足,无法使 string2 足够大以添加标题,草图仍然保持稳定运行并且不会崩溃。
输出应该是
这是锅炉房的温度 27.4 摄氏度,
但现在缺少标题。27.4
摄氏度
意事项:
1) 草图持续运行,因为在 UNO 和 Mega2560 上,堆内存分配始终保持 128 字节的__malloc_margin,因此堆栈始终至少有那么多空间可用于保持程序运行。如果您有大量嵌套方法调用和大量局部变量,则可能会导致草图崩溃,但这种情况极其罕见。2
) 在方法中使用本地字符串比使用 char[] 更安全,因为如果内存不足,本地字符串内存分配就会失败,并且始终至少留下 128 个字节的空闲空间。而本地 char[] 堆栈分配永远不会失败,它们只会覆盖堆并导致内存损坏。
总结:当您使用字符串时,UNO 和 Mega2560 以及其他基于 AVR 的主板在内存不足的情况下非常稳定。草图继续运行,但字符串会丢失一些文本。
浙公网安备 33010602011771号