Подтвердить что ты не робот

Насколько плохо использовать динамические массивы данных на встроенной системе?

Таким образом, во встроенном системном блоке, который я возьму в следующем году, мы узнаем, что динамические структуры данных - это плохо, что есть во встроенной системной программе. но в лекционных заметках не говорится, почему.

Теперь я работаю над небольшим масштабом, встроенный контроллер "LURC", в основном, просто использует преимущества периферии демонстрационной платы "Butterfly" для AVR169MEGA. выдает 4 сигнала PWM для сервоуправления и ESC. а также предоставить 9-сегментный ЖК-экран.

Теперь я не могу придумать какой-либо способ хранения инструкций, так как они получают серийный номер USART, чем очередь. esp для вещей, где мне нужно подождать, пока не будет получено неизвестное количество данных: например, строка, отображаемая на ЖК-экране.

так почему бы вам не использовать динамические структуры данных на микроконтроллере во встроенных системах? Это просто, что вы в значительной степени ограничены окружающей средой, и должны быть уверены, что ваши mallocs преуспевают?

4b9b3361

Ответ 1

Существует несколько причин не использовать malloc (или эквивалент) во встроенной системе.

  • Как вы упомянули, важно, чтобы вы не внезапно оказались вне памяти.
  • Фрагментация - встроенные системы могут работать в течение многих лет, что может привести к серьезной трате памяти из-за фрагментации.
  • Не требуется. Динамическое распределение памяти позволяет повторно использовать одну и ту же память, чтобы делать разные вещи в разное время. Встраиваемые системы имеют тенденцию делать то же самое все время (кроме при запуске).
  • Скорость. Динамическое распределение памяти является относительно медленным (и становится медленнее по мере фрагментации памяти) или довольно расточительно (например, приятельская система).
  • Если вы собираетесь использовать одну и ту же динамическую память для разных потоков и прерываний, тогда подпрограммы распределения/освобождения должны выполнять блокировку, что может вызвать проблемы с обслуживанием прерываний достаточно быстро.
  • Распределение динамической памяти очень затрудняет отладку, особенно с некоторыми из инструментов ограниченного/примитивного отладки, доступных во встроенной системе. Если вы статически выделяете материал, тогда вы знаете, где материал все время, что означает, что гораздо проще проверить состояние чего-то.

Лучше всего - если вы не динамически выделяете память, вы не можете получить утечки памяти.

Ответ 2

Ну, у многих небольших микроконтроллеров нет ничего похожего на MMU или на ОС с красивой кучей, с которой вы можете работать.

Для тех, кто это делает, до тех пор, пока вы держите разумную привязку к объему памяти, о которой вы просите, я действительно не вижу в ней огромной проблемы.

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

Ответ 3

Мое впечатление, что во встроенной системе я точно знаю, сколько памяти доступно, и мне разрешено использовать ровно 100%; нет необходимости оставлять бит для других (одновременно работающих) программ, но также нет виртуальной памяти, чтобы дать мне 101-й процент. Поэтому для очереди я могу легко вычислить, что у меня есть место для (скажем) 981 записей; поэтому я создаю массив для этих записей, и если мне когда-либо понадобится 982-я запись, я буду fscked вверх и должен найти способ потерпеть неудачу изящно.

Ответ 4

Это зависит от того, как значение "встроенный" на мой взгляд расширилось за последние 4 года.

Традиционно встроенные устройства имели на них микроконтроллеры и вообще не имеют операционной системы. Нет защищенной памяти, и они были однопоточными. Вы должны быть предельно осторожны с malloced памятью, потому что так легко выбежать из нее, когда у вас есть только 32 КБ ее, например, доступной. В общем, мы будем писать наш код с буферами фиксированного размера и никогда не будем использовать malloc или, если он будет использоваться каждый раз - очень экономно.

В последние несколько лет мы видим, что по существу одночиповые ПК или микро-платы, которые так же мощны, как и наши старые ПК Pentium. Цены на RAM сейчас настолько дешевы и настолько малы, что ограничения памяти ничем не отличаются. Они также часто запускают встроенный linux или вздрагивают, так что теперь у нас есть возможность использовать динамическую память более либерально.

С помощью этой возможности можно использовать гораздо более широкий диапазон языков, включая Java, С++, многие языки сценариев и другие языки, которые обеспечивают защиту от переполнения буфера и обработку исключений и другие языки более высокого уровня. Так что действительно, эти старые проблемы не такие, как раньше.

Я подозреваю, что все это новое доступное оборудование выходит на новый уровень проблем.

Ответ 5

Нет ничего плохого в динамической памяти во встроенной среде как таковой, хотя обычно она не покупает вас во встроенной среде.

По-моему, это очень хорошая идея использовать кольцевые буферы (это очень простая структура данных для драйверов ввода-вывода и т.д.). Таким образом, если по какой-то причине вы не можете обслуживать свою очередь, использование памяти по-прежнему детерминировано.

Используя некоторые макросы, можно выделить структуры переменных размера во время компиляции.

Например -

    //we exploit the fact that C doesn't check array indices to allow dynamic alloc of this struct
    typedef struct ring_buf_t {
        int element_sz,
            buffer_sz,
            head,
            tail;
        char data[0];
    } ring_buf_t;

   #define RING_BUF_ALLOC_SZ(element_sz,n_elements) (sizeof (ring_buf_t) + \
                                                      (element_sz) * (n_elements))

    char backing_buf[RING_BUF_ALLOC_SZ (sizeof(type_to_buffer), 16)];

    //ring_buf_init() casts backing buf ring_buf_t and initialises members...
    ring_buf_t *ring_buffer = ring_buf_init (element_sz, n_elemements, backing_buf);

;

Этот шаблон представляет собой динамически значимый буфер с использованием памяти guarenteed. Конечно, структуры данных других типов (списки, очереди и т.д.) Могут быть реализованы таким же образом.

Ответ 6

Я бы сказал, что и нехватка памяти, и проблема неудачного malloc. Последнее представляет большую проблему, поскольку у вас нет ОС/интерфейса для спасения системы от такого сбоя. Очень опасно использовать функцию, которая может помещать вашу полную систему, которая может работать без головного убора, в визг остановки (или, возможно, вызывать reset, все еще плохо).

Ответ 7

Динамические структуры данных на встроенных системах немного напоминают указатели на С++. Указатели (на С++) являются злыми. Но иногда это единственный вариант; иногда они являются меньшим злом; и иногда это нормально, чтобы полностью их избежать. В тех случаях, когда есть веские основания для их использования, могут быть "хорошие" способы и "плохие" способы сделать это.

Статически распределенные переменные и массивы намного быстрее выделяют и освобождают и могут быстрее обращаться к динамически распределенным данным. См. этот ответ.

Динамически выделяемые (под которыми я имею в виду malloc() ed или аналогичные) данные также требуют пространственных накладных расходов, чтобы отслеживать распределения. По меньшей мере несколько байтов на рассылку - это пространство может быть очень ценным для встроенных систем!

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

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

Ответ 8

Я не знаю об Atmel MEGA169, но MEGA168, который, я полагаю, связан с 169, имеет только 1024 байта SRAM. Он также имеет только 16 тыс. Программных ПЗУ и относительно медленный по сравнению с современными компьютерами. Таким образом, он ограничен в памяти, размере и скорости программы.

В моем опыте программирования AVR-ассемблера требуется много усилий, чтобы максимально использовать функциональность в ПОС. Объем накладных расходов, необходимых для использования динамических структур данных (дополнительное использование памяти, дополнительные инструкции, необходимые для вытягивания и выталкивания данных из SRAM, отслеживание динамической переменной, где происходит перемещение блоков памяти, когда переменные "между" удаляются...) просто не оправдывает заслуги.

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