Размер стека по отношению к виртуальной памяти

На уроке «Операционные системы» мы упоминали виртуальную память как механизм, который абстрагирует физическую память для процесса, и что она выглядит примерно так (для каждого процесса):

Стек увеличивает адреса памяти, а куча увеличивает адреса памяти. Начальный адрес стека — это практически максимальный адрес адресного пространства (около 2^64 — 1 на 64-битном процессоре).

Я понимаю виртуальную память, стек и кучу, но не понимаю, почему размер стека должен быть ограничен всего парой МБ, исходя из этой картины (на практике стеки составляют всего несколько МБ из-за кэширования и больших размеров стека). указать на проблему в коде). Теоретически переполнение стека должно происходить только тогда, когда у нас заканчивается системная память, а не когда мы заполняем 1-3 МБ.

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

Эта картина страдает от серьезной депривации реальности.

user3344003 25.04.2024 16:09

@user3344003 user3344003 Я не совсем понял, что ты имеешь в виду

lukascobbler 28.04.2024 17:05

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

user3344003 06.05.2024 19:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Поскольку вы обычно заранее знаете, какого уровня стека будет достаточно, вполне приемлемо ограничить размер стека и разрешить беспрепятственный доступ к куче. Стек размером 1 М на самом деле довольно велик, если вы помещаете только базовые типы (включая указатели). Например, если усреднить (и это немало) десять восьмибайтовых параметров на вызов (и удвоить их для дополнительного использования административного стека), то это более 6000 уровней стека, которые вы можете пройти, не исчерпав стек.

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

Чтобы ответить на ваш конкретный вопрос (о дополнительной «линии разрыва»): иногда размер стека устанавливается компоновщиком, когда он объединяет все объектные файлы в исполняемый файл. Например, я считаю, что редактор связей GNU ld использует (или когда-то использовал) сценарий с указанным размером стека.

Я смутно помню, как пользовался системами (давно)(1), где размер стека был жестко запрограммирован в компоновщике и был достаточно мал, чтобы причинить нам горе. Следовательно, мы просто использовали основной поток для запуска другого потока (без ограничения размера, поскольку стек был где-то выделен из кучи) для выполнения реальной работы. Затем основной поток просто ждал завершения другого потока.

Вы абсолютно правы в том, что вы могли бы просто разделить это пространство между низом кучи и верхом стека, чтобы они оба могли свободно его использовать.


(1) Ограничение распространялось только на исходный стек, настроенный загрузчиком программы на основе информации из исполняемого файла. Даже сейчас это ограничение может применяться, а может и не применяться к стекам, создаваемым на лету при создании дополнительных потоков внутри процесса.

То есть конечная строка стека не существует в концепции виртуальной памяти, но она существует, когда компоновщик завершает свою работу?

lukascobbler 22.04.2024 13:15

@lukascobbler: могут существовать искусственные ограничения, такие как фиксированный селектор Intel с ограниченным размером 2 МБ, который не расширяется, когда вы его исчерпаете (или даже тот, который может быть расширен операционной системой, но он решает прекратить расширение на 8 МБ), но эти на самом деле это детали реализации. В обычном 64-битном адресном пространстве с плоской моделью существование этих ограничений не требуется.

paxdiablo 22.04.2024 13:26

Это имеет большой смысл и отвечает на мой вопрос. Спасибо.

lukascobbler 22.04.2024 13:36

Другие вопросы по теме