Как сохранить стековое пространство с хорошим дизайном?

try:
    failedCmd = 'A'
    1/10 # -command A-
    failedCmd = 'B'
    1/0 # -command B-
    failedCmd = 'C'
    1*0 # -command C-
    failedCmd = ''
except:
   print("The exception occured during command " + failedCmd)

Выход

The exception occured during command B
12
задан John Topley 27 September 2008 в 07:58
поделиться

10 ответов

Попытайтесь сделать стек вызовов более плоским, таким образом, вместо a() вызов b() который звонит c() который звонит d(), иметь a() звонить b(), c(), и d() самостоятельно.

Если на функцию только ссылаются однажды, отметьте ее inline (принятие Вашего компилятора поддерживает это).

11
ответ дан 2 December 2019 в 04:34
поделиться

Существует 3 компонента к Вашему использованию стека:

  • Обратные адреса Вызова функции
  • Параметры Вызова функции
  • автоматические (локальные) переменные

Ключ к уменьшению Вашего использования стека должен минимизировать передачу параметров и автоматические переменные. Потребление пространства самого фактического вызова функции довольно минимально.

Параметры

Один способ решить проблему параметра состоит в том, чтобы передать структуру (через указатель) вместо большого количества параметров.


foo(int a, int b, int c, int d)
{
...
   bar(int a, int b);
}

сделайте это вместо этого:


struct my_params {
   int a;
   int b;
   int c;
   int d;
};
foo(struct my_params* p)
{
   ...
   bar(p);
};

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

Автоматические переменные (местные жители)

Это имеет тенденцию быть крупнейшим потребителем стекового пространства.

  • Массивы являются уничтожителем. Не определяйте массивы в своих локальных функциях!
  • Минимизируйте количество локальных переменных.
  • Используйте самый маленький необходимый тип.
  • Если повторная входимость не является проблемой, можно использовать статические переменные модуля.

Следует иметь в виду, что при простом перемещении всех локальных переменных от локального объема до объема модуля Вы НЕ оставили свободного места. Вы обменяли стековое пространство на пространство сегмента данных.

Некоторые RTOS поддерживают локальную память потока, которая выделяет "глобальное" устройство хранения данных на основе на поток. Это могло бы позволить Вам иметь несколько независимых глобальных переменных на на основание задачи, но это сделает Ваш код не как простой.

10
ответ дан 2 December 2019 в 04:34
поделиться

В конечном счете можно сэкономить много оперативной памяти, но иметь только маленький клочок стека, я предлагаю оценить статические выделения.

В C "автоматически управляют всеми переменными, объявленными в функции", что означает, что они выделяются на стеке.

Квалификация объявлений как "статичные" хранит их в оперативной памяти вместо на стеке. Они в основном ведут себя как глобальные переменные, но все еще позволяют Вам избегать дурных привычек, которые идут со злоупотреблением globals. Можно сделать хороший случай для объявления больших, долговечных буферов/переменных как статичный для снижения давления на стеке.

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

6
ответ дан 2 December 2019 в 04:34
поделиться

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

С GCC попытайтесь добавить "-finline-функции" (или-O3) флаг и возможно флаг "-finline-limit=n".

5
ответ дан 2 December 2019 в 04:34
поделиться

Один прием, который я считал где-нибудь inorder для оценки требований стека кода во встроенной установке, должен заполнить стековое пространство в начале с известным шаблоном (МЕРТВЫЙ в шестнадцатеричном числе, являющемся моим фаворитом) и позволять системе, выполненной некоторое время.

После нормального выполнения считайте стековое пространство и посмотрите, сколько из стекового пространства не было заменено в ходе операции. Дизайн, чтобы оставить по крайней мере 150% что, чтобы заняться всеми obsure путями выполнения кода, которые, возможно, не были осуществлены.

1
ответ дан 2 December 2019 в 04:34
поделиться

Можно ли заменить некоторые локальные переменные globals? Массивы в особенности могут съесть стек.

Если ситуация позволяет Вам совместно использовать некоторый globals между некоторыми globals между функциями, существует шанс, можно уменьшить след памяти.

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

Какие переменные Вы имеете в своих функциях? О чем размеры и пределы - мы говорящий?

0
ответ дан 2 December 2019 в 04:34
поделиться

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

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

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

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

0
ответ дан 2 December 2019 в 04:34
поделиться

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

Обычно ваше программное обеспечение будет расти (новые функции, ...), поэтому, если у вас есть чтобы начать проект с размышлений о том, как сохранить пространство стека, которое было обречено с самого начала.

0
ответ дан 2 December 2019 в 04:34
поделиться

Да, ОСРВ действительно может съесть оперативную память для использования стека задач. Мой опыт показывает, что как новый пользователь RTOS имеет тенденцию использовать больше задач, чем необходимо.

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

0
ответ дан 2 December 2019 в 04:34
поделиться

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

Стек выделяется до выполнения main (). Когда вы вызываете функцию b () из функции a (), адрес области хранения сразу после последней переменной, используемой a, передается в b (). Это становится началом стека b (), если b () затем вызывает функцию c (), тогда стек c начинается после последней автоматической переменной, определенной b ().

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

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

Еще одна уловка для систем с ограниченной памятью - разделить занимающие память части функции на отдельные автономные функции.

0
ответ дан 2 December 2019 в 04:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: