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

С++ - Локальные массивы стека по сравнению с динамическим распределением

При программировании на C/С++; как правило, какова точка отсечения, где вместо char array[MAX_PATH+1]={0} можно использовать:

 char *array=nullptr;

 array=new char [MAX_PATH+1];

 ...code...

 delete [] array;

В какой момент нужно сохранить пространство в стеке?

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

4b9b3361

Ответ 1

Компонент устанавливает размер стека. Любое статическое распределение будет обрабатываться до 1 ГБ на окнах (может отличаться в других системах). Однако размер стека по умолчанию для окон составляет 1 МБ (8 МБ в Linux). Таким образом, основное преимущество динамического распределения заключается в том, что вы не знаете размер перед рукой или если у вас есть очень большие ассигнования, необходимые для вашей программы.

Ответ 2

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

Без виртуальной памяти (например, на небольших микроконтроллерах), как правило, доступно меньше памяти. Если ваша программа выделяет слишком много места в стеке, она просто переполняет стек и записывает все, что находится за пределами пространства, зарезервированного для стека. Вы можете отложить больше пространства стека, чтобы справиться с наихудшим случаем, но тогда это пространство предназначено для стека все время, если вам это нужно или нет. В то время как при динамическом распределении вы платите только за его использование, и вы можете проверить код возврата malloc, чтобы определить, произошел ли сбой (или исключить исключения из new для людей, пытающихся сжать С++ в микроконтроллер). В качестве альтернативы, вы можете статически зарезервировать раздел ОЗУ для объекта, если приложение всегда нуждается в нем, потому что таким образом он имеет более предсказуемое поведение во время выполнения, и вам не нужно беспокоиться о фрагментации.

В виртуальной памяти ОС может динамически наращивать стек, добавляя страницы к смежным виртуальным адресам в конце стека. Таким образом, вы платите только физическую память за стек суммы, который вы используете. Однако, с небольшим (32-битным битом или менее?) Адресным пространством, вы все равно можете столкнуться с проблемами, если у вас много потоков и слишком много выделения стека.

Каждый поток должен иметь непрерывное пространство для своего стека и должен делиться со всем остальным в системе. Например, если ОС занимает 1 ГБ адресного пространства (не редкость), и вы хотите 1 ГБ для стеков потоков, это оставляет вам 2 ГБ для кучи, данных и кода. Если у вас есть 16 потоков, это означает, что вы можете иметь около 64 МБ на стек потока. Что может быть или не совсем нормально в зависимости от вашего приложения.

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

20 лет назад на 4 ГБ адресного пространства было много места для кучи, данных, кода и стека - не так много сегодня. К счастью, адресные пространства тоже стали больше. С 64-разрядным адресным пространством вы исчерпаете DRAM задолго до того, как сможете исчерпать физическую память - даже если у вас более 1 ТБ DRAM.

Несколько предостережений

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

  • OS/run-time не так хороша в том, чтобы вернуть пространство стека, как оно есть при его использовании. Поскольку ваша программа занимает больше места в стеке, она получит новые страницы. Эти страницы, скорее всего, не будут освобождены до тех пор, пока поток не выйдет (по крайней мере, это было так). Если вы используете пространство стека, это не имеет большого значения. Если он используется редко и поток работает долгое время, память будет заменена на диск, если у вас есть резервное хранилище (обычно это не проблема для рабочего стола/ноутбука с вращающимся диском, но, возможно, это не так хорошо для iOS8 или Android 64 -битных).

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

Ответ 3

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

В современной системе вы можете легко сделать:

char array [123456];

но вы не сделали бы этого в функции, которая вызывает себя повторно через рекурсию.