Недавно при разработке контроллера столкнулся со странной ситуацией. При вызове функции String::replace() иногда возникала ошибка: результирующая строка содержала не тот текст, который я ожидал. В некоторых случаях конец строки "затирался" или состоял из символов явно не в той кодировке.
При получении подобных ошибок первое, что приходит в голову: ошибка в адресациях или указателях. Действительно, подобные ошибки могут быть связаны с неправильным использованием памяти, например когда идет передача указателя на переменную, которая уже может не существовать на этот момент. Тогда результат обращения к ней будет зависеть от того, перезаписана ли память новыми данными, и мы получим в итоге похожие симптомы.
Но я проверил несколько раз все места в коде, где могли быть подобные ошибки, но код был абсолютно корректный.
В программе был один момент, который и подсказал мне разгадку: я реализовывал функционал небольшого web-сервера, а для этого неминуемо пришлось передавать и обрабатывать довольно длинны строки, содержащие код html-шаблонов и заголовков http запросов. Большие конечно только по меркам Arduino Uno, которая имеет всего 2кб оперативной памяти. Вот память и закончилась. А при переполнении памяти вы никак об этом не узнаете, кроме как по возникшим ошибкам.
Итак, признаки того, что у вас закончилась ООП:
- ошибки "плавающие", возникают не всегда
- в программе есть функционал обработки длинных строк или работы с большими числами
- в качестве платформы вы используете Arduino Uno, Arduino Nano или другую плату с малым количеством ООП
- при выводе значений переменных в сериальный порт в вывод попадают символы в кривой кодировке, подстроки из прошлых выводов и тд
Но это все косвенные признаки. Для того же, чтобы точно понять, что проблема именно в нехватке памяти, можно воспользоваться библиотекой MemoryFree.
А можно и не подключать библиотеку, а просто добавить в проект 2 файл: MemoryFree.h и MemoryFree.cpp, их код есть на https://playground.arduino.cc/Code/AvailableMemory/.
Далее просто в нужных местах кода, где вы предполагаете, что память закончилась, расставить:
#include <MemoryFree.h>
...
Serial.print("freeMemory()=");
Serial.println(freeMemory());
Близкое к 0 значение или же отрицательное говорит о проблеме с нехваткой памяти.
Вот пара советов, как этого избежать:
- пополнить знания о работе с памятью в C++ (особенно если ваш опыт связан с разработкой на более высокоуровневых и/или скриптовых языках)
- на первое время чаще в процессе разработки использовать функцию freeMemory(), пока экономия памяти не отложится в вашей памяти :)
- если в программе есть функционал обработки больших строк или больших данных, то лучше выбрать плату с большим количеством памяти, как то Arduino Mega или даже Arduino Due
- чаще очищать неиспользуемые переменные
- длинные текстовые константы определять с использованием ключевого слова PROGMEM, тогда для их хранения будет использована flash-память, размер которой сильно превышает размер ООП
Пример использования PROGMEM:
#include <avr/pgmspace.h>
...
const char long_text[] PROGMEM = "Длинный текст, которые не меняется в процессе работы программы";
...
Arduino Mega с 8кБ ООП:
Arduino Due с 96кБ ООП: