У меня обычно не возникает проблем с выбором, должны ли некоторые данные быть глобальными, статическими или размещаться в стеке (здесь нет динамического выделения, поэтому не нужно использовать кучу). Я также прочитал несколько вопросов и ответов, таких как этот, но мой вопрос более конкретный, поскольку он включает в себя огромный объем данных, огромный по сравнению с системной памятью.
Я работаю над существующим кодом, который пытаюсь улучшить (дизайн, возможные проблемы, производительность и т. Д.). Этот код работает на старом 8-битном MCU с 4 КБ ОЗУ . В этом коде я сталкиваюсь с использованием массива почти 1 КБ (да, 1 КБ в системе ОЗУ 4 КБ ). Каждый байт этого массива используется, это не вопрос. Проблема в том, что этот массив является статическим массивом в файле, в котором он объявлен, поэтому его жизненный цикл такой же, как и у программного (то есть его можно считать бесконечным).
Однако после прочтения кода я только что обнаружил, что этот массив не нуждается в бесконечном жизненном цикле, он построен и обрабатывается полностью процедурно, поэтому мы должны иметь возможность объявить его только в той функции, в которой он используется, таким образом, это будет в стеке, и поэтому мы будем экономить 1 КБ ОЗУ.
Теперь вопрос: будет ли это хорошей идеей? С точки зрения дизайна, если ему не нужен бесконечный / глобальный жизненный цикл, он принадлежит стеку. Но эй, это 1 КБ из 4 КБ, нет ли недостатка в выделении 25% ОЗУ, как это? (это может быть 50% или более от стека)
Может ли кто-то поделиться некоторым опытом с такой ситуацией, или кто-то думает о какой-либо уважительной причине не помещать этот массив в стек? Я ищу технические недостатки, а также комментарии по дизайну.
Единственное, что я осознаю, это то, что я должен убедиться, что у меня на самом деле есть 1 КБ стека при входе в эту функцию. Может быть, это все, что я должен позаботиться, а может и нет.
Ответы:
Да, и это сильное ограничение. Тебе лучше быть статически уверенным, чем иметь такое большое пространство в стеке. Если код маленький, если вы используете GCC для компиляции кода, посмотрите это .
Кстати, некоторые дешевые микропроцессоры могут использовать «большой» кадр вызова более дорогостоящим, чем «нормальный» (например, потому что их набор команд предпочтет однобайтовое смещение от указателя стека). YMMV.
Кроме того, если вы пишете код на C и чувствуете, что ваш большой массив может повторно использовать пространство для других целей, вы можете рассмотреть возможность сделать его членом объединения (с глобальной переменной
union
типа). Да, это довольно некрасиво.В качестве альтернативы вы можете подумать о кодировании некоторого примитивного распределителя кучи, подходящего для вашего приложения (и он может иметь API, отличный от
malloc
&free
....).источник
gcc -flto -Os
? ) и вы могли бы получить немного памяти ....Люди, как правило, осторожны с большим стеком, потому что он увеличивается в ОЗУ и перезаписывает значения переменных, что приводит к необъяснимому поведению. Это становится еще хуже, потому что вам нужно знать минимально возможный адрес указателя стека и вычитать размер, выделяемый при входе в подпрограмму.
Это все работа для аппаратного управления памятью (должна генерировать ловушки или сбои при переполнении стека) или для компилятора, если у него есть функции для этого вида анализа.
В противном случае вы можете делать то, что вы хотите с вашей оперативной памятью.
источник
Как указывалось в предыдущих ответах, я бы также рекомендовал оставить массив статическим, если он умещается в памяти. В большинстве случаев гораздо важнее иметь детерминированный след памяти, даже если это означает, что вы «тратите» память на переменные, которые не используются постоянно. Размещение больших массивов в вашем стеке слишком легко уничтожит его, а переполнение стека может привести к трудностям при поиске и воспроизведении (если вы не можете использовать MMU для защиты стека).
Предложение об обмене блоком с некоторыми другими данными с объединением является допустимым для IMO, хотя оно также может быть источником труднодоступных проблем, если вы найдете в нем неправильные переменные.
Если вам не хватает памяти, и вам крайне необходимо создать кратковременные переменные для совместного использования, прежде чем перемещать массив в стек, я хотел бы рассмотреть возможность динамического выделения памяти, даже если у него есть свои недостатки. В этом случае это может быть не ответ, так как массив звучит довольно большой по сравнению с доступной памятью.
источник
У вас есть еще один вариант, если у вас есть какой-то флеш-накопитель. Вы можете обменять скорость доступа на оперативную память, храня свои данные во флэш-памяти и читая и ища там. Вам нужно будет загружать только одну запись за раз в оперативную память. Это будет немного сложнее, если вам нужно будет обновить записи. Вам понадобится сегментированный износостойкий механизм. Я делал это в прошлом и включил индекс для ускорения доступа.
источник
Особенно при работе со встроенными системами вы хотите, чтобы как можно больше сбоев происходило во время компиляции, и ничего не происходило во время выполнения (хотя, если бы мы могли этого добиться, было бы неплохо ...)
Создание больших массивов, которые могут вам понадобиться в произвольно выбранных состояниях вашей программы, статически делает именно это - компоновщик в конечном итоге предупредит вас «это не помещается в ОЗУ», тогда как выделение стека просто приведет к аварийному завершению вашей программы с трудным для отладки стеком. переполняется.
источник