2016-09-26 1 views
0

Предположим, что у меня есть функция, вызванная из замкнутого цикла, которая выделяет несколько массивов POD (без конструкторов) в стеке в одном сценарии, а я распределяю массивы динамически один раз и повторно их использую на каждой итерации. Локальные массивы добавляют затраты времени выполнения или нет?Какова стоимость создания больших локальных массивов в стеке на C и C++?

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

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

  • Кэширование: это стек, обработанный особым образом кэшем ЦП или он не отличается от остальной информации?

  • Являются ли переменные массивы различными по отношению к вышеуказанному? Скажем, для массивов с постоянным размером стек может быть каким-то образом предварительно распределен (или предварительно вычислен с помощью компилятора?), Тогда как для вариативных есть что-то еще, что добавляет затраты времени исполнения. Опять же я понятия не имею, как это работает.

+2

Выберите язык. Это разные языки с очень разными компиляторами. И укажите свою платформу – kfsone

+0

C++ не имеет массивов переменной длины. – kfsone

+0

@kfsone: для них нет стандартного синтаксиса (но), но обычно можно получить автоматическое хранилище переменной длины через '_alloca()' –

ответ

2

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

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

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

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

+0

Кэш гораздо сложнее. Нет простого «стек будет горячим в кеше». Это также зависит от ассоциативности. Это даже ухудшило распределение больших массивов в стеке. Также выравнивание может ухудшить производительность при использовании стека. Без надлежащего профилирования на современных платформах конкретные предположения о поведении более спекулируют, чем что-либо еще. – Olaf

1

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

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

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

+0

«Так будет, в общем, намного быстрее использовать стек памяти» - чистая спекуляция без истинного основания. Это зависит от фактического применения. Действительно, правильно и разумно распределенная динамическая память может быть намного быстрее. Без конкретного прецедента невозможно сказать. – Olaf

+0

@Olaf «чистая спекуляция без истинного основания». Вы действительно думаете, что просто набрасывание указателя стека на получение «большего» стека не будет «вообще ... намного быстрее», чем через 'malloc()' или «новый» стек вызовов с его блокировкой, размещением и выделением подходящего блока памяти и возвратом его при освобождении блокировки (-ов)? Даже если это «правильно и разумно распределено», это не будет быстрее, чем добавление некоторого значения в содержимое регистра указателя стека. «Но стека, возможно, придется расти» Ну, так может быть и куча. –

+0

1) Стандарт C не применяет конкретный алгоритм. 2) Это не имеет значения, если вы предварительно распределите блоки и, например, используйте бассейн. 3) Если время обработки в этом буфере является доминирующим, выравнивание и т. Д. Становится более важным. И много других проблем (банки RAM, кэширование и т. Д.). Я явно не ссылался на распределение. Тогда стек может быть в различной памяти, обычно быстрее, но ограниченным по размеру и т. Д. OP даже не указывает свою целевую арку. – Olaf

Смежные вопросы