Освобождение памяти в Stack'e

344
24 декабря 2016, 14:54

Всем известно,что с Stack это некий участок памяти,который аллоцируется на каждый поток в виде размера 1МБ , в нем хранятся ссылки(ObjRef) на ReferenceType,пользовательские структуры,примитивные данные,ну и локальные переменные метода.

А теперь вопрос: что делает CLR, когда Stack полностью заполниться, и соответственно удалять по сути нечего.То бишь Stack переполнен?

Может ли CLR расширить его границы с 1МБ до 2МБ?(или это не возможно,в связи с чем,мы просто получим Exception, который оповестит нас о переполнении стека).

Другой вопрос: в контексте unsafe кода,unamanged участку памяти выделяется так же 1МБ или аллоцировать можно кастомный размер?

Answer 1

Для начала стоит отметить что стек в момент выполнения кода - это не какой-то абстрактный safe-механизм. .NET использует JIT-компиляцию, так что в реальности выполняется код, привязанный к конкретной платформе, с использованием механизма стека этой платформы. В случае x86 - сегмент стека + пара регистров SS/ESP и операциями push/pop. Никакого отдельного стека для unsafe не создается.

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

Дело в том, что стек, по крайней мере в x86/64 - это структура данных, заполняемая с конца. Т.е. каждое помещение чего-то в стек сдвигает его указатель ближе к началу. Это идет из древних (еще до-.net) времен, когда памяти было мало, и стандартное разделение памяти выглядело так:

[код][данные-куча --> ....... пустое место....... <-- данные-стек]

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

С тех пор многое поменялось (хотя раскладка выше все еще актуальна на некоторых микроконтроллерах). В x86 Для стека теперь обычно выделен отдельный сегмент. Но он, по традиции, заполняется с конца. Т.е. каждая операция push уменьшает значение SP на размер положенного в стек.

По достижению ESP значения 0 - процессор выбрасывает ошибку. Механизма "довыделения памяти" в стеке в x86 нет - просто потому, что нельзя "довыделить" память в начало сегмента - а выделить память в конце и переложить все данные в стеке процессор не осмеливается - для него это слишком сложная операция. Это могла бы сделать операционная система, но по крайней мере Windows на x86 так не поступает.

На выходе по достижению 0 указателем стека вы получаете StackOverflowException в вашем коде .NET. Это индикатор достижения лимита "железного" стека, а не какого-то хитрого стека CLR.

Стоит отметить, что к StackOverflowException на x86 может привести также бесконечная рекурсия, причем даже в случае если вы не объявляете локальные переменные. Дело в том, что механизм вызовов методов на x86 (call) сохраняет в стеке адрес возврата из вызываемого метода. А оператор возврата (ret) достает адрес из стека. Поэтому слишком глубокая цепочка вызовов забивает стек.

Собственно, именно поэтому окно просмотра вызовов и называется Call Stack - информация цепочке возврата хранится только в стеке. Причем на x86 - в том же физическом стеке что и параметры фунций и локальные переменные.

READ ALSO
Не дописывает в файл все значения

Не дописывает в файл все значения

Данный код выполняет запись в файл (выполняется в Windows 10):

366
Работа с Word посредством C#

Работа с Word посредством C#

Здравствуйте! Возможно ли как-то после какой-то N строки, сделать так сказать скриншот следующих строк и вывести их потом отдельно в виде картинки(или...

821
Методы расширения LINQ

Методы расширения LINQ

Есть список товаров List<Product>, в котором Product имеет свойства стоимость Cost и группа GroupМожете привести пример как использовать метод расширения,...

501
загрузка и распаковка архивов в c#

загрузка и распаковка архивов в c#

У меня есть программа на с, которая загружает документы ворд, а затем нужное содержимое документа раскидывает по таблице DataGridViewТеперь нужно,...

389