Сегодняшние ПК имеют большой объем физической ОЗУ, но, тем не менее, размер стека C # составляет всего 1 МБ для 32-разрядных процессов и 4 МБ для 64-разрядных процессов ( емкость стека в C # ).
Почему размер стека в CLR все еще так ограничен?
И почему именно 1 МБ (4 МБ) (а не 2 МБ или 512 КБ)? Почему было решено использовать эти суммы?
Меня интересуют соображения и причины этого решения .
c#
stack
clr
stack-size
Николай Костов
источник
источник
Thread
конструктора. НО, возникает вопрос, зачем вам стек побольше?1572864
размер стека в байтах по умолчанию (получено с помощью GetCurrentThreadStackLimits Win32 API). Я могуstackalloc
примерно1500000
байты без StackOverflowException.Ответы:
Вы смотрите на парня, который сделал этот выбор. Дэвид Катлер и его команда выбрали один мегабайт в качестве размера стека по умолчанию. Ничего общего с .NET или C #, это было решено при создании Windows NT. Один мегабайт - это то, что он выбирает, когда заголовок EXE программы или вызов WinAPI CreateThread () не указывает размер стека явно. Это нормальный способ, почти любой программист оставляет за ОС выбирать размер.
Этот выбор, вероятно, предшествовал дизайну Windows NT, история на этот счет слишком туманна. Было бы неплохо, если бы Катлер написал об этом книгу, но он никогда не был писателем. Он оказал огромное влияние на то, как работают компьютеры. Его первой разработкой ОС была RSX-11M, 16-разрядная операционная система для компьютеров DEC (Digital Equipment Corporation). Это сильно повлияло на CP / M Гэри Килдалла, первую достойную ОС для 8-битных микропроцессоров. Что сильно повлияло на MS-DOS.
Следующим его проектом была VMS, операционная система для 32-битных процессоров с поддержкой виртуальной памяти. Очень успешный. Его следующий был отменен DEC примерно в то время, когда компания начала распадаться, будучи не в состоянии конкурировать с дешевым компьютерным оборудованием. Намек Microsoft, они сделали ему предложение, от которого он не мог отказаться. Многие из его сотрудников тоже присоединились. Они работали на VMS v2, более известной как Windows NT. DEC расстроилась из-за этого, деньги перешли из рук в руки. Я не знаю, выбрал ли VMS уже один мегабайт, я достаточно хорошо знаю только RSX-11. Это не маловероятно.
Достаточно истории. Один мегабайт - это много , реальный поток редко занимает больше пары горстей килобайт. Так что мегабайт на самом деле довольно расточительно. Однако это вид потерь, который вы можете себе позволить в операционной системе с виртуальной памятью с подкачкой страниц по запросу, поскольку мегабайт - это просто виртуальная память . Просто цифры для процессора, по одному на каждые 4096 байт. На самом деле вы никогда не используете физическую память, ОЗУ в машине, пока не обратитесь к ней.
Это чрезмерно для .NET-программы, потому что размер в один мегабайт изначально был выбран для размещения собственных программ. Которые, как правило, создают большие кадры стека, сохраняя в стеке также строки и буферы (массивы). Печально известный как вектор атаки вредоносных программ, переполнение буфера может манипулировать программой данными. Не так, как работают программы .NET, строки и массивы размещаются в куче сборщика мусора и проверяется индексация. Единственный способ выделить место в стеке с помощью C # - использовать ключевое слово unsafe stackalloc .
Единственное нетривиальное использование стека в .NET - это джиттер. Он использует стек вашего потока для своевременной компиляции MSIL в машинный код. Я никогда не видел и не проверял, сколько места требуется, это скорее зависит от характера кода и от того, включен ли оптимизатор, но пара десятков килобайт - это приблизительное предположение. В противном случае этот веб-сайт получил свое название, переполнение стека в программе .NET довольно фатально. Не осталось достаточно места (менее 3 килобайт) для надежного JIT любого кода, который пытается перехватить исключение. Кабум на рабочий стол - единственный вариант.
И последнее, но не менее важное: .NET-программа делает со стеком что-то довольно непродуктивное. CLR зафиксирует стек потока. Это дорогое слово, означающее, что оно не просто резервирует размер стека, оно также гарантирует, что пространство зарезервировано в файле подкачки операционной системы, поэтому при необходимости стек всегда можно заменить. Отказ от фиксации является фатальной ошибкой и безоговорочно завершает программу. Это происходит только на машине с очень маленьким объемом оперативной памяти, которая выполняет слишком много процессов, такая машина перейдет на патоку до того, как программы начнут умирать. Возможная проблема 15+ лет назад, а не сегодня. Программисты, которые настраивают свою программу так, чтобы она работала как гоночный автомобиль F1, используют этот
<disableCommitThreadStack>
элемент в своем файле .config.Фуив, Катлер не переставал разрабатывать операционные системы. Это фото было сделано, когда он работал над Azure.
Обновление, я заметил, что .NET больше не фиксирует стек. Не совсем уверен, когда и почему это произошло, я слишком давно не проверял. Я предполагаю, что это изменение дизайна произошло где-то около .NET 4.5. Довольно разумное изменение.
источник
The only way to allocate space on the stack with C# is with the unsafe stackalloc keyword.
- Локальные переменные, например,int
объявленные внутри метода, не хранятся в стеке? Я так думаю.maxStackSize
потока? Мне не удалось найти его на [MSDN] ( msdn.microsoft.com/en-us/library/5cykbwz4(v=vs.110).aspx ). Основываясь на ваших комментариях, кажется, что использование стека является абсолютным минимумом, и я могу использовать наименьшее значение для размещения максимально возможных потоков. Спасибо.Размер зарезервированного стека по умолчанию определяется компоновщиком, и разработчики могут изменить его, изменив значение PE во время компоновки, или для отдельного потока, указав
dwStackSize
параметр дляCreateThread
функции WinAPI.Если вы создаете поток с начальным размером стека, большим или равным размеру стека по умолчанию, то он округляется до ближайшего кратного 1 МБ.
Почему значение равно 1 МБ для 32-битных процессов и 4 МБ для 64-битных? Я думаю, вам следует спросить разработчиков, которые разработали Windows, или подождать, пока кто-нибудь из них ответит на ваш вопрос.
Наверное, Марк Руссинович это знает, и вы можете связаться с ним. ним . Возможно, вы найдете эту информацию в его книгах «Внутренние устройства Windows», предшествующих шестому изданию, в которых содержится меньше информации о стеках, чем в его статье . Или, может быть, Раймонд Чен знает причины, так как он пишет интересные вещи о внутреннем устройстве Windows и ее истории. Он тоже может ответить на ваш вопрос, но вы должны опубликовать предложение в поле для предложений .
Но в этот раз я попытаюсь объяснить некоторые возможные причины, по которым Microsoft выбрала эти значения, используя MSDN, блоги Марка и Раймонда.
Значения по умолчанию имеют эти значения, вероятно, потому, что в ранние времена ПК были медленными и выделение памяти в стеке было намного быстрее, чем выделение памяти в куче. И поскольку выделение стека было намного дешевле, они использовались, но для этого требовался больший размер стека.
Таким образом, значение было оптимальным размером зарезервированного стека для большинства приложений. Это оптимально, потому что позволяет выполнять множество вложенных вызовов и выделять память в стеке для передачи структур вызывающим функциям. В то же время это позволяет создавать множество потоков.
В настоящее время эти значения в основном используются для обратной совместимости, поскольку структуры, которые передаются как параметры функциям WinAPI, по-прежнему размещаются в стеке. Но если вы не используете выделение стека, то использование стека потока будет значительно меньше, чем 1 МБ по умолчанию, и, как сказал Ханс Пассан, это расточительно. И чтобы предотвратить это, ОС фиксирует только первую страницу стека (4 КБ), если другая не указана в PE-заголовке приложения. Остальные страницы размещаются по запросу.
Некоторые приложения переопределяют зарезервированное адресное пространство и изначально настроены на оптимизацию использования памяти. Например, максимальный размер стека потока собственного процесса IIS составляет 256 КБ ( KB932909 ). И такое уменьшение значений по умолчанию рекомендует Microsoft:
Источники:
источник