Делает ли меньшие функции в целом более эффективными с точки зрения памяти, поскольку переменные освобождаются чаще? - PullRequest
2 голосов
/ 11 августа 2011

Делает ли работа на 5 функций больше, чем одна большая функция, более эффективна память в C, поскольку в данный момент в памяти меньше переменных, так как кадр стека освобождается чаще? Зависит ли это от компилятора и оптимизации? если да, то в каких компиляторах это быстрее?

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

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

Ответы [ 5 ]

2 голосов
/ 11 августа 2011

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

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

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

Если вы помещаете в стек огромные структуры (несколько килобайт) или если вы работаете на машине, где килобайт занимает много памяти, это может повлиять на общее использование памяти. Итак, если под «множеством локальных переменных» вы подразумеваете несколько десятков int с и указателей, то нет, ничего, что вы делаете, не имеет существенного значения. Если под «большим количеством локальных переменных» вы подразумеваете несколько десятков буферов по 10 тыс., Или если ваша функция рекурсивно разворачивается так, что у вас есть сотни уровней из ваших нескольких десятков int с, то, по крайней мере, это может иметь значение в зависимости от ОС и конфигурации.

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

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

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

[*] Людям, программирующим на C для PIC или чего-то подобного, использующим компилятор C, который по сути является неоптимизирующим ассемблером, разрешается оскорблять, что я назвал их компилятор «не стоящим». Стек на таких устройствах настолько отличается от «типичных» систем, что в любом случае ответ будет другим.

1 голос
/ 11 августа 2011

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

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

0 голосов
/ 11 августа 2011

Разделение огромной функции на более мелкие имеет свои преимущества, среди них потенциально более оптимизированное использование памяти.

Скажем, у вас есть эта функция.

void huge_func(int input) {
    char a[1024];
    char b[1024];
    // do something with input and a
    // do something with input and b
}

И вы разделили его на два.

void func_a(int input) {
    char a[1024];
    // do something with input and a
}

void func_b(int input) {
    char b[1024];
    // do something with input and b
}

Вызов huge_func займет как минимум 2048 байт памяти, а вызов func_a, тогда func_b достигнет того же результата с примерно наполовину меньше памяти. Однако, если внутри func_a вы звоните func_b, объем используемой памяти будет примерно таким же, как huge_func. По сути, то, что написал @ sje397.

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

0 голосов
/ 11 августа 2011

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

0 голосов
/ 11 августа 2011

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

С точки зрения памяти, я думаю, что если вы действительно разбиваете работу (f, то g,затем h) затем вы увидите, что некоторое увеличение доступной памяти будет незначительным, но если они взаимозависимы, то этого не произойдет.

Как говорит @Joel Burget, управление памятью на самом деле не рассматривается при структурировании кода.

Просто мой дубль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...