STL в встроенной системе с очень ограниченной памятью

В настоящее время я занимаюсь созданием встроенной системы с использованием процессора ARM Cortex M3 с 64 КБ SRAM. На данный момент я ищу способ обеспечить детерминированную производительность с помощью контейнеров STL, что включает в себя обеспечение того, что я не могу закончиться нехваткой памяти во время выполнения.

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

Я работаю с другими людьми в этом проекте, которые не хотят беспокоиться о необработанном распределении памяти и предпочитают использовать "хорошо известные" структуры данных (стек, очередь, deque и т.д.). Поэтому в настоящее время я рассматриваю возможность создания оберток вокруг C-массивов для обеспечения этих структур. Это позволит статически распределять память, необходимую для поддержки этих контейнеров, и позволяет другим разработчикам знать размер контейнера, который они создали до времени выполнения, на основе информации о размере кода, предоставленной компилятором. На мой взгляд, это гарантирует, что проблемы с отключением памяти не могут произойти во время выполнения и значительно упростить разработку системы.

Другим вариантом будет выделение контейнеров STL при инициализации системы. После периода инициализации дополнительного распределения динамической памяти не произойдет. Однако, насколько мне известно, стандартные структуры данных С++ STL не поддерживают это - для этого потребуется, чтобы контейнеры, такие как стек, могли быть предварительно выделены (аналогично вектору).

Я был бы признателен за любые замечания относительно моего предложения по созданию классов вокруг стандартных C-массивов? Кроме того, существует ли более простой способ для размещения статического размера STL-контейнера, такого как статический размер стека или очереди, во время компиляции? (Я знаю, что это возможно с помощью вектора, но другие я не уверен)

Примечание. Я прочитал другой вопрос (Embedded С++ для использования STL или нет)), но автор этого вопроса не пояснил, сколько памяти они имели (другие тогда, как они использовали процесс ARM7) или, похоже, рассматривают решение, подобное моему.

Второе примечание. Я знаю, что для некоторых разработчиков 64 КБ SRAM может показаться большой памятью. Фактически, я сделал разработку на процессорах AVR со значительно меньшим объемом памяти, поэтому я понимаю эту перспективу. Однако из моего текущего (возможно, неинформированного) представления, 64 КБ памяти не так много, когда речь идет о контейнерах STL.

Ответ 1

Этот вопрос путается и странно. Во-первых, позвольте прояснить некоторые заблуждения.

Вы называете "стек, очередь, deque" по имени. Ну, два из них не являются контейнерами. stack и queue - контейнерные адаптеры. Видите, они фактически не хранят элементы непосредственно; они просто посредничают интерфейсу с ними. stack гарантирует, что вы можете только нажать, поп и получить верхний элемент. queue гарантирует, что вы можете только назад, поп-фронт и получить передний элемент (подумайте, что он также позволяет получить задний элемент).

Контейнерные адаптеры фактически принимают в качестве одного из своих параметров шаблона фактический тип контейнера для использования. Поэтому вы можете использовать stack с std::list, если хотите. Я бы не стал предлагать это (в зависимости от вашего варианта использования), но вы могли бы.

Контейнерные адаптеры не заботятся о памяти; это контейнеры, которые они используют, которые выделяют память.

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

Например, если у вас есть vector, который должен работать в пределах 2 Кбайт памяти, если он имеет размер 1 КБ и пытается выделить 2,5 КБ больше, распределитель не может просто вернуть 2 КБ. Он может либо вернуть 2.5KB по запросу, либо бросить std::bad_alloc. Это ваши два варианта. Для распределителя нет возможности сообщить vector, что он может получить больше памяти, чем то, что у него есть, но не так, как хочет.

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

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

Я предлагаю отследить копию EASTL. Это действительно предназначено для такого рода вещей. Репо Github я связал вас с некоторыми исправлениями ошибок и т.д., Но он по-прежнему в основном тот же. Это не плохой код. Их STL-подобные контейнеры обеспечивают большую часть интерфейса, поэтому они могут быть в основном заменой замены. Но они обеспечивают специальную функциональность для специфического управления выделениями памяти.

Ответ 2

Помимо EASTL, вы также можете использовать static_vector от повышения. Он разделяет большую часть API с помощью std::vector, и его можно использовать с контейнерными адаптерами (очередь, стек). Вместо того, чтобы бросать std::bad_alloc, он может вызывать throw_bad_alloc(), поэтому его также можно использовать во встроенной среде без исключений.

Ответ 3

Я знаю, что это старый поток, но для тех, кто заинтересован, я поддерживаю STL-подобную библиотеку шаблонов для встроенных приложений. Нет использования кучи вообще.

Встроенная библиотека шаблонов (лицензия MIT) https://www.etlcpp.com