Динамическое выделение памяти для встроенного приложения

Я работаю над проектом, который требует использования MCU для приема пакетов кадров с неизвестной длиной кадра при приеме, но каждый прием имеет октет, из которого вы можете вывести количество кадров, оставшихся для приема, и, следовательно, вычислить длину всего кадра .

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

Например. Если мы предположим, что пакеты состоят из 20 октетов, а 3-й октет сообщает вам количество оставшихся октетов, которые нужно получить (это может быть максимум 2, 3 и даже 17 октетов). Вместо того, чтобы создавать регистр размером 17, который может не использоваться, как я могу динамически выделить эту память, особенно для встроенного приложения, так что, если 3-й октеты упиваются тем, что есть 6 октетов для приема, то я просто выделяю зарегистрируйте размер 6 для остальной части кадра, не используя «malloc».

Язык программирования — С.

Надеюсь, мой вопрос достаточно ясен. Пожалуйста, поделитесь своим мнением, так как мне нужно наилучшим образом подойти к этому.

Спасибо.

Есть ли причина, по которой вы не хотите использовать malloc?
Какое преимущество дает вам неиспользование дополнительной памяти? Вам все равно придется выбирать размер MCU, чтобы иметь достаточно оперативной памяти для самого большого пакета, который вы можете получить.
@Bruno, не могли бы вы посоветовать использовать malloc для встроенного приложения с размером ОЗУ около 2 КБ и учетом того факта, что память сопряжена.
@markrages Я понимаю вашу точку зрения, но я хочу посмотреть, есть ли способ сэкономить память, потому что фактический максимальный размер составляет около 128 байт, что не всегда полностью используется, так почему бы не помочь использовать оставшуюся память для других операций ?
Что ты собираешься делать с оставшимися? Вы должны быть готовы к максимальному размеру пакета, не так ли?
@ПолА. Это зависит от количества свободной памяти, которая у вас есть. Имейте в виду, что использование схемы динамического распределения всегда связано с накладными расходами, поэтому, если размер ваших данных не намного превышает 20 байт, лучше использовать блоки фиксированного размера.
Вы должны уточнить, что вы подразумеваете под «MCU». Если вы говорите о крошечном встроенном процессоре, который больше ничего не делает, ответ таков: выделите всю свою память для работы, не беспокоясь о динамическом распределении. Если это 32-битный ARM с Linux, и есть много других вещей, использующих память, тогда да, используйте динамический режим. Сколько памяти в системе и что еще ее использует?

Ответы (2)

В этом случае я бы сказал, что лучший подход, вероятно, состоит в том, чтобы просто выделить максимальный размер памяти и повторно использовать ее для как можно большего количества других вещей.
В некоторых компиляторах есть возможность для переменных совместно использовать пространство памяти, если они не активны одновременно. Например, компилятор PIC18 C (теперь замененный на HI-Tech C) имеет атрибут overlay, который можно использовать для этого с переменными.
Он также может обрабатывать массивы переменного размера, которые идеально подходят для того, что вы хотите сделать (меньше накладных расходов, чем malloc). Я бы проверил, может ли ваш компилятор это сделать.

@ойл Глейзер. Спасибо за этот момент. Я использую компилятор keil и Atmel studio 6. Я знаю, есть ли у них такие возможности!
Согласитесь, это плохой вариант для динамического размещения, особенно на встроенной платформе; динамическое выделение наиболее полезно, когда вы буквально не знаете, сколько памяти потребуется, т. е. взаимодействие с пользователем провоцирует выделение памяти. Если я что-то не упустил, похоже, вам нужно достаточно места для максимального количества пакетов максимального размера в худшем случае, так почему бы не выделить столько памяти вместо того, чтобы перепроектировать решение? Кроме того, если вы пойдете по динамическому маршруту на платформе с ограниченным объемом памяти и не будете осторожны, вас укусит ворчливый друг динамического распределения — фрагментация.

Во многих системах с микроконтроллерами компиляторы и компоновщики размещают данные в нижней и/или верхней части ОЗУ; неиспользуемая оперативная память обычно находится в непрерывной области, и, как правило, можно убедить компоновщика сделать адреса начала и конца этой области доступными для программиста (например, можно попросить компоновщика поместить однобайтовую переменную в качестве самая последняя вещь перед свободной областью, а другая — самой первой после; адреса этих переменных очерчивают свободное пространство).

Хотя многие системы предлагают malloc()функцию, во многих сценариях она сложнее, чем необходимо. Например, если нужно выделить объекты на основе информации, полученной во время выполнения, но объекты всегда будут освобождаться в порядке, обратном выделению, можно просто сохранить указатель на «следующее доступное пространство». Чтобы выделить объект, скопируйте этот указатель, добавьте к нему размер нового объекта и верните скопированный указатель. Чтобы освободить объект (и все, что находится после него), просто установите указатель «следующее доступное пространство» на начало этого объекта.

Некоторые сценарии немного сложнее, чем это было бы разрешено при таком подходе, но все же не нуждаются в полном подходе «malloc/free». Например, в некоторых сценариях может быть две группы объектов, которые между собой подчиняются правилу «последний пришел — первый ушел», но объекты в одной группе могут пережить объекты в другой. Чтобы справиться с этой ситуацией, используйте указатель «следующее доступное пространство», который начинается снизу свободного пространства, и указатель «предыдущее доступное пространство», который начинается вверху. Распределите вещи в первой группе, как и раньше. Для тех, кто во второй группе, вычтите размер нового объекта из указателя «предыдущее доступное пространство» и верните результат. Чтобы освободить объект второй группы (и все объекты второй группы, расположенные после него),

Обратите внимание, что mallocиfreeспроектированы таким образом, что объекты в середине памяти могут быть освобождены, в то время как объекты до и после остаются действительными. Хотя иногда это может быть полезно, это также может привести к фрагментации памяти. Если чьи-либо объекты не соответствуют модели «последний пришел — первый ушел», может быть хорошей идеей сделать объекты перемещаемыми. Например, можно хранить очередь объектов переменного размера, которые последовательно сохраняются в памяти до тех пор, пока есть место. Когда память заполняется (или в какое-то удобное время до этого), можно было бы скопировать первый объект, который еще не был прочитан, в начало очереди, следующий объект, который не был прочитан сразу после него, и т. д. до тех пор, пока все объекты были скопированы, а свободное место, которое было в начале очереди, объединено в конец. Нужно быть осторожным при перемещении любых данных, чтобы убедиться, что указатели на эти данные обновляются соответствующим образом, но часто это не слишком сложно. Перемещение памяти может занять больше циклов ЦП, чем управление прерывистыми областями свободного пространства, но поведение подхода с перемещением памяти может быть более предсказуемым.