Отладка максимальной емкости
1. Пример
Проверьте приведенную ниже программу для Arduino Nano, Old Bootloader, для переменных значений N
.
- Для низких значений (
N<=1857
) программа выводит"[FFFFFFFF]"
, - Для более высоких значений (
1858<=N<=1953
) программа выводит непредсказуемые варианты этой строки, - Для более высоких значений (
1954<=N<=1955
) программа выдает ошибку заполнения символа"["
, - Выше определенного значения (
1956<=N
) программы не выводят ни одного символа.
Я не проверял тщательно эти результаты, которые на самом деле могут сильно отличаться и полностью зависеть от платформы, но, думаю, воспроизводимы.
Обратите внимание, что динамическое размещение не используется.
Обратите внимание, что все инициализировано, первые значения 4
равны 0xFF
, следующие значения N-3
равны 0x00
(Ссылка).
Компиляция не показывает никаких релевантных предупреждений, демонстрируя скромное использование емкости на 10 %.
Sketch uses 3206 bytes (10%) of program storage space. Maximum is 30720 bytes.
Global variables use 196 bytes (9%) of dynamic memory, leaving 1852 bytes for local variables. Maximum is 2048 bytes.
Из этого примера видно, как вычислить правильное значение N
, действительно можно ожидать проблемы, связанной с емкостью (Ссылка).
Обратите внимание, что эти значения намного меньше "предположительного" значения N=32767
для 1-байтовых переменных (?) (Ref.).
2. Проблема
Теперь, со значительно огромной реальной программой, у меня та же проблема с этими неожиданными результатами, поэтому я почти уверен (несколько минут назад), что это является причиной.
При превышении некоторого "~максимального~" уровня программа начинает давать сбои, а при "~освобождении~" этой мощности программа начинает работать нормально (конечно, без удаленного функционала!).
3. Вопрос
Как мне отлаживать, измерять, измерять или предотвращать эту ситуацию, а также указывать, когда следует оставить этот процессор, а когда следует перейти на более крупный, когда явно компилятор не является разумным предположением?.
// ПРОВЕРКА ЕМКОСТИ
#include <SoftwareSerial.h>
// УСТАНОВИМ ПРАВИЛЬНОЕ ЗНАЧЕНИЕ N
// N<=1857: последний допустимый результат
// 1858<=N<=1953: Последний наблюдаемый вывод - один символ
// ПК=0x0444. [AVR MEMORY] Запись в ячейку памяти 0x0948 вне размера памяти 0x0900. [UP0]
// 1954<=N<=1955: Последний наблюдаемый результат — наводнение
// Неверный код операции 0xFFFF на ПК=0xA402
// ПК=0x0444. [AVR MEMORY] Запись в ячейку памяти 0x0948 вне размера памяти 0x0900. [UP0]
// 1956<=N: Нет вывода
// Неверный код операции 0xFFFF на ПК=0xA402
#define N 1857
void setup()
{
Serial.begin(38400);while (!Serial){;}
byte a[N+1]={0xFF,0xFF,0xFF,0xFF};
char si[3];
Serial.print("[");
for (int i1=0;i1<=N-1&&a[i1]!=0;i1++){
sprintf(si,"%02X",a[i1]);
Serial.print(si);
}
Serial.print("]");
}
void loop(){}
@Brethlosze, 👍1
Обсуждение1 ответ
Лучший ответ:
От нижней до верхней части оперативной памяти у вас есть:
- раздел .data (статически выделенные инициализированные переменные)
- раздел .bss (статически размещенные неинициализированные переменные)
- куча (динамическое выделение с помощью
malloc()
иnew
) - свободное место
- стек (обратные адреса и автоматическое выделение локальных переменных)
См. воспоминания Arduino для получения более подробной информации. обсуждение.
Размеры разделов .data и .bss известны во время сборки. Этот это использование памяти «Глобальные переменные», сообщаемое в конце компиляция. Остальная часть оперативной памяти доступна для кучи и куча. Это количество указано как «осталось 1852 байта для локального переменные», где «локальные переменные» — это небольшое упрощение.
Ваш пример программы не использует выделение кучи. Он использует некоторые
статическое выделение, в основном для буферов Serial
и много стека
для:
- адреса возврата из вызовов
main()
иsetup()
(4 байт) - локальные массивы
a
иsi
(N+4 байта) - память, необходимая для
sprintf()
илиSerial.print()
(неизвестно)
Даже игнорируя последний пункт, видно, что вся оперативная память будет
потребляется, когда 4 + N + 4 = 1852, т. е. N = 1844. Когда вы сделаете N больше, чем
это значение, стек упирается в раздел .bss, и вы начинаете
повреждая ваши глобальные переменные. Описываемое вами поведение
в соответствии с программой, повреждающей внутренние структуры данных
объект Серийный
.
Как мне отлаживать, измерять, измерять или предотвращать эту ситуацию
Не существует простого способа заранее определить объем кучи и стек, который будет потреблять ваша программа. Обычное решение состоит в том, чтобы измерить и сообщить об этом во время во время выполнения. См., например, библиотеку MemoryFree. (есть много подобных этому).
- Proteus - Как отладить недопустимый код операции?
- Нужна помощь с библиотекой U8GLIB
- Не удается загружать скетчи в Arduino Nano Every
- Помогите уменьшить размер скетча!
- Serial.println использует слишком много памяти (не строки)
- Проблемы с памятью? dtostr() и strcat()
- Стирание 1 байта внешней Flash памяти (winbond)
- Почему Serial.print(1) требует на 228 байт больше программной памяти по сравнению с Serial.print((char)(48+1))?
Ваши числа находятся в пределах предела SRAM для Arduino Nano (2 КБ). Существует различие между языковым ограничением AVR GCC и ограничением SRAM для данной платы/MCU., @Mikael Patel