Arduino глобальные переменные используют динамической памяти

Arduino.ru

Ошибка при загрузке скетча // Недостаточно памяти, программа может работать нестабильно.

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Помогите пожалуйста решить проблему. При загрузке скетча пишет:

Скетч использует 10894 байт (75%) памяти устройства. Всего доступно 14336 байт.Глобальные переменные используют 1000 байт (97%) динамической памяти, оставляя 24 байт для локальных переменных. Максимум: 1024 байт.

ЗАРАНЕЕ СПАСИБО. Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Какую проблему-то решить? Памяти допаять вам в МК что ли?

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Помогите пожалуйста решить проблему.

А проблема-то есть? Она работает или нет? Ну, мало памяти, но может хватает? Вы уж толком говорите.

А так — какие проблемы? Сокращать память, как я понимаю для Вас не вариант, ну тогда берите Мегу — туда влезет.

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Фигня все это, у меня один скетч при 90 % стабильно уж пару месяцев работает, зависит от самого скетча, количества вызовов процедур (стек), количества сторонних библиотек и ещё кучи причин.

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Вряд ли будет работать, стоит переходить на иной камень. Мой ХШ подсказывает, что сама программа отожрет в худшем случае около 10 байт со стека. Но, в ней активно работает lcd.print(), который есть наследник как и Serial.print() от всего стека классов stream, а там жрется не так уж и мало, вот сколько точно уже не помню, но вряд ли меньше 14 байт. Там тучно есть около 9 вложенных вызовов «друг в друга», из-за чего и делал свою часть библиотеки — аналога работы с LCD, а это явно уже 18 байт стека как миниум, без локальных переменных.

ТС, даже интересно, работает стабильно или куда? :)

Источник

Arduino.ru

глобальные\локальные переменные

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Имеем вот такую инфу:

объясните плиз что такое глобальные переменные..

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Имеем вот такую инфу:

объясните плиз что такое глобальные переменные..

Никакого другого смысла в Ардуино этому панятию не назначается.

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Объясните плиз что надо оптимизировать, чтоб уменьшить этот параметр? Просто макетирую на чипе нано, а использовать хотел более простой\дешевый про мини 168.. а туда это явно не влезет :)

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Невозможно оптимизировать то, чего нету.

P.S. а где вы откопали ПроМини на 168 аттмеге?

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Объясните плиз что надо оптимизировать, чтоб уменьшить этот параметр?

Нужно уменьшеать количество глобальныйх переменных (например, делая их локальными) и их размер (например, используя byte вместо int, где это допустимо).

Еще следует избавиться от копирования констант в оперативную память (см. PROGMEM).

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Спасибо. VOID я так понимаю тоже жрет интересующий меня ресурс памяти.. :) А у меня все в процедурках..

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Спасибо. VOID я так понимаю тоже жрет интересующий меня ресурс памяти.. :) А у меня все в процедурках..

Что-то вы не так понимаете.

На самом деле — изменение типа int на byte поможет только если у вас емкий массив этих величин. А жрут больше всего экземпляры классов из подключаемых библиотек.

Покажите код — может и подскажем, чего.

оно вам действительно нужно?

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

относительно ответов — огромное спасибо.

сегодня говорил с заказчиком автоматики — код паказывать смысла особого нет. ибо он еще будет дописываться. следовательно еще выростет.

что касается вопроса: оно вам действительно нужно?

— просто было интересно куда убегают ресурсы.. ., когда писал свой первый код даже не представлял чем можно забить всю память :)

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

что касается вопроса: оно вам действительно нужно?

— просто было интересно куда убегают ресурсы.. ., когда писал свой первый код даже не представлял чем можно забить всю память :)

Я спросил про ПроМини на 168 аттмеге, учитывая, что на 328 стоит столько-же.

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

я их заказал по 1.2 бакса десяток. думал в эти пульты втыкать :) ну пойдут куда то в другие игрушки..

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Возможно кому то пригодится. Оказывается Serial.print здорово жрет ресурсы.

Убрал вывод данных в последовательный порт. количество глобальных переменных сократилось с 82% до 55% :)

Источник

Arduino.ru

Куда делась память? Глобальные переменные используют 1658 байт (80%) динамической памяти.

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

попробуй так, сколько места занимать будет?

Глобальные переменные используют 210 байт (10%) динамической памяти

т.е. не изменилось ВООБЩЕ, по отношению с использованием F.

Это потому что макрос F() — тоже обёртка над FlashStringHelper, деда просто другим способом записал. Он имел в виду — насколько изменилось по сравнению без использования F() ;)

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

попробуй так, сколько места занимать будет?

Глобальные переменные используют 210 байт (10%) динамической памяти

т.е. не изменилось ВООБЩЕ, по отношению с использованием F.

ну тоись вот это

Куда делась память? Глобальные переменные используют 1658 байт (80%) динамической памяти.

не твоё? или 10% и 80% это примерно одинаковые величины?

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

короче, WEB программирование это не моё, пойду лучше напьюсь, за здоровье одного здешнего математика.

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

короче, WEB программирование это не моё, пойду лучше напьюсь, за здоровье одного здешнего математика.

Не рано ишшо? Хотя да, о чём это я — напицца никогда не рано :)

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

Я WEB программист (PHP и JS).

Собственно это всё, что нужно знать о современном вебе! ;)

Всё зависит от чистоты в голове и прямых рук. Подавляющее большинство веб программистов, не отличаются умом и то что они пишут просто ужас. А выставляют себя так как будто мега крутые. У наст так один проект взломали из-за того что на аутсорсе был у таких. Не надо говорить что язык говно или веб программисты недоразвитые. Есть отдельные случаи. Просто зайти в веб намного проще, чем в тот-же си. Как начал делать проекты на ардуино, я находил кучу в инете, скажем откровенно, «говна» который выкладывается за истину. Поэтому не будем обобщать.

Источник

Работа с динамической памятью

Динамическая память

Чаще всего во время работы мы используем локальные и глобальные переменные: промежуточные вычисления делаем в локальных, объекты классов библиотек создаём глобально и пользуемся ими в программе и так далее. Не углубляясь в программу можно понять, в каком месте доступна конкретная переменная, где её область определения, т.е. где она существует. Если мы видим имя такой переменной в коде – мы с уверенностью можем сказать, что в данном месте программы эта переменная существует. Её значение находится в памяти и мы можем с ним работать напрямую, прочитать или изменить его, а также “измерить” вес этой переменной. Дело в том, что жизненный цикл таких переменных известен заранее, они не могут менять свой размер в процессе работы программы, не могут появиться или исчезнуть в другое время или в другом месте, работа с ними проста и понятна.

Но что делать, если нам нужно например принять данные неизвестного размера? Или нужно использовать несколько условных “библиотек” на глобальной области определения программы, но оперативной памяти для всех не хватит? На помощь приходит динамическая память: мы можем создавать переменные (выделять память) прямо в процессе работы программы и удалять их оттуда. В любое время, в любом месте, как душе угодно.

Распределение памяти

В этом уроке научимся работать с динамической памятью микроконтроллера. Прежде всего нужно ознакомиться с распределением памяти и понять, как оно работает и что мы вообще будем делать. Перед вами схема распределения памяти в МК от AVR, которые стоят на Arduino. Во многих других архитектурах оперативная (SRAM) память устроена похожим образом:

Память – это по сути большой массив, каждая ячейка которого имеет свой адрес, адрес растёт слева направо (по картинке выше). Первым идёт Flash, она же программная память, память, в ней хранится код программы. Во время работы программы этот код не меняется (есть способы сделать это, но это не относится к теме урока).

Сегодня нас интересует динамическая память, SRAM, которая на схеме представлена совокупностью синей, зелёной, розовой и оранжевой областей, а также белой областью со стрелочками между розовой и оранжевой. Рассмотрим подробнее:

  • Globals (синий и зелёный) – в этой области живут глобальные и статические переменные. Размер этой области известен на момент запуска программы и не меняется в процессе её выполнения, т.к. глобальные и статические переменные уже объявлены, их размер и количество известны.
  • Stack, он же стек (оранжевый) – в этой области живут локальные переменные и аргументы функций. Размер этой области меняется во время выполнения программы, стек растёт от конца области памяти в сторону уменьшения адресов, навстречу куче (см. стрелку на схеме). Переменные, которые тут живут, называются автоматическими: программа сама выделяет память (при создании локальной переменной) и сама эту память освобождает (локальная переменная удаляется при выходе из функции). Важно: процессор не контролирует размер стека, то есть во время работы стек может врезаться в кучу и перезаписать находящиеся там данные.
  • Heap (розовый), она же куча – из этой области мы можем самостоятельно выделить память под свои нужды. Размер этой области может меняться во время выполнения программы, куча “растёт” в сторону увеличения адресов, слева направо, что показано стрелкой на схеме. Эту память мы контролируем сами: сами выделяем и сами освобождаем. Важно: процессор не даст вам выделить область, если свободной памяти под неё недостаточно, т.е. наползание кучи на стек маловероятно.

Выделение памяти

Для выделения и освобождения динамической памяти “из кучи” у нас есть готовые инструменты. При выделении памяти мы получаем адрес на первый байт выделенной области и его нужно будет хранить в указателе (читайте предыдущий урок про адреса и указатели).

  • malloc(количество) – выделяет количество байт динамической памяти и возвращает адрес на первый байт выделенной области. Если свободной памяти недостаточно для выделения – возвращает “нулевой указатель” – NULL ( nullptr ).
  • free(ptr) – освобождает память, на которую указывает указатель ptr . Освободить можно только память, выделенную при помощи функций malloc() , realloc() или calloc() . В выделяемой области хранится размер этой области (+2 байта), и при освобождении функция free сама знает, какой размер освобождать.
  • new и delete – технически те же самые malloc() и free() , разница в применении (см. пример ниже)

Рассмотрим пример с выделением и освобождением памяти при помощи malloc/free и new/delete. Примеры абсолютно одинаковые с точки зрения происходящего, отличаются только синтаксисом:

malloc-free

Есть ещё две функции: calloc() и realloc() :

  • calloc(количество, размер) – выделяет память под количество элементов с размером размер каждый (в байтах). Тот же malloc, но чуть удобнее использовать: в примере выше мы умножали, чтобы получить нужное количество байт для хранения int malloc(20 * sizeof(int)) , а можно было вызвать calloc(20, sizeof(int)); – заменив знак умножения на запятую.
  • realloc(ptr, размер) – изменяет величину выделенной памяти, на которую указывает ptr, на новую величину, задаваемую параметром размер. Величина размер задается в байтах и может быть больше или меньше оригинала. Возвращается указатель на блок памяти, поскольку может возникнуть необходимость переместить блок при возрастании его размера. В таком случае содержимое старого блока копируется в новый блок и информация не теряется.

new-delete

Динамические объекты

Иногда бывает нужно использовать условную “библиотеку” на большой области определения, но делать это не на всём протяжении работы программы, т.е. иногда выделять объект из памяти, работать с ним, а затем удалять. Под библиотекой я в данном случае подразумеваю класс или структуру, т.к. 99.99% библиотек являются классами (читай урок про классы и объекты). С точки зрения программы, объект – это тоже переменная, просто “комплексная”. Мы всегда можем создать указатель на объект и использовать его динамически (не забываем, что оператор “точка” . превращается в “стрелочку” -> , см. урок про указатели). Абстрактный пример со стандартной библиотекой Servo, в которой объект создаётся динамически, а затем выгружается из памяти при повороте на заданный угол:

Фрагментация

Мы можем зарезервировать себе область памяти, можем её освободить. Что может пойти не так?

  1. Если последовательно несколько раз выделить память, участки будут располагаться друг за другом.
  2. Если освободить участок, выделенный раньше предыдущих – в памяти останется “дырка”: занятые области не сдвигаются на освободившееся место!
  3. Если продолжить выделять память, программа будет примерять новую область сначала на “дырки”, а затем уже на свободную область в куче.
  4. Если неаккуратно обращаться с динамической памятью – эта самая память может закончиться гораздо быстрее, чем ожидалось!

Потерял ключи

Как вы могли видеть из примеров выше – освобождение блока памяти производится по указателю, то есть мы указываем, с какого адреса нужно освобождать память. Это означает, что нам ни в коем случае нельзя терять указатель, иначе мы не сможем освободить память! Это как потерять ключи от дома =) Абстрактный пример:

Существует ли переменная?

Как определить, существует ли на данный момент выделенная переменная и можно ли с ней работать? Очень просто: у нас ведь есть указатель на неё. Если передать указатель в условие, то он покажет true , если адрес ненулевой (переменная существует в памяти), и false – если нулевой (переменная не существует в памяти, обращаться по указателю нельзя). Возвращаясь к примеру с Серво, можно поступить так:

То есть если объект существует (по указателю), то работаем с ним.

Но есть пара моментов, о которых нужно помнить, если в программе проводится такая проверка на существование:

  • Локально созданный указатель может быть ненулевым. Если при создании указателя локально вы не выделяете память сразу, то лучше задать его нулём, приравняв к NULL или nullptr : int* val = nullptr;
  • При освобождении памяти указатель не сбрасывается в ноль! Делаем это вручную:

Вес динамической переменной

Если зачем-то понадобилось узнать вес динамической переменной, то нужно не перепутать, что измерять: мы работаем с указателем, а у указателя есть значение (тип), на которое он указывает. Например выделим байт памяти: byte* b = new byte;

  • Если измерить как sizeof(b) – результат будет 2 байта (AVR) и 4 байта (esp8266/esp32), потому что это – вес указателя, который зависит от разрядности адресного пространства микроконтроллера, т.е. результат не зависит от типа и веса данных!
  • Если измерить как sizeof(*b) – получим 1 байт, именно столько и весит байт, а мы измеряли размер данных по указателю.

Пакетное управление памятью

Итак, выделять и освобождать память мы научились, теперь рассмотрим несколько инструментов для удобной работы с динамической памятью:

  • memset(ptr, значение, количество) – заполняет область памяти, на которую указывает ptr, байтами значение, в количестве количество штук. Часто используется для задания начальных значений выделенной области памяти. Внимание! Заполняет только байтами, 0.. 255.
  • memcpy(ptr1, ptr2, количество) – переписывает байты из области ptr2 в ptr1 в количестве количество. Грубо говоря переписывает один массив в другой. Внимание! Работает с байтами!

Зачем?

Новичку работа с динамической памятью не понадобится, но знания будут полезны при изучении чужого кода. Также с динамической памятью мы сталкиваемся каждый раз, когда используем String-строки, которые являются динамическими массивами. Удобно, не правда ли?

Источник

Adblock
detector