Что ж, извините, если это похоже на повторение старых вопросов, я прошел через несколько вопросов о переполнении стека, Книге современных операционных систем от tanenbaum, и мне еще предстоит прояснить мои сомнения по этому поводу.
Во-первых, я был бы признателен за любую книгу / ресурс, который я должен пройти более подробно, чтобы лучше понять эту структуру. Я не понимаю, являются ли эти концепции в общих чертах объясненными в книгах по ОС, или в языках программирования или в архитектуре.
Прежде чем задавать свои вопросы, я опишу свои выводы на основе чтений о стеках / кучах
отвал
стек
Теперь несколько вопросов о том же.
Я знаю, что это много, и я, кажется, очень запутался, я был бы признателен, если бы вы указали мне правильное направление, чтобы разобраться в этих вещах!
Глобальные переменные размещаются в статическом разделе памяти, который располагается во время компиляции. Значения инициализируются во время запуска до main
введен Инициализация может, конечно, распределять в куче (то есть статически распределенной std::string
будет иметь саму структуру в статически расположенной памяти, но строковые данные, которые она содержит, будут выделены в куче во время запуска). Эти вещи удаляются при нормальном завершении работы программы. Вы не можете освободить их раньше, если хотите, вы можете заключить значение в указатель и инициализировать указатель при запуске программы.
Куча управляется библиотекой-распределителем. Есть одна, которая поставляется со средой выполнения C, но есть и такие, как tcmalloc или же jemalloc что вы можете использовать вместо стандартного распределителя. Эти распределители становятся большими страницы памяти из операционной системы с помощью системных вызовов, а затем дать вам части этих страниц при вызове malloc. Организация кучи несколько сложна и варьируется между распределителями, вы можете посмотреть, как они работают на своих сайтах.
Да-иш. Хотя вы можете использовать библиотечные функции, такие как alloca
чтобы освободить место в стеке и использовать его для чего угодно.
Каждый процесс имеет отдельное пространство памяти, то есть он думает, что он один, и никакого другого процесса не существует. Как правило, операционная система даст вам больше памяти, если вы об этом попросите, но она также может применять ограничения (например, ulimit
на Linux), когда он может отказаться дать вам больше памяти. Фрагментация не проблема для ОС, потому что она дает память в страницы. Однако фрагментация в вашем процессе может привести к тому, что ваш распределитель запросит больше страниц, даже если есть свободное место.
Да.
Да, однако, как правило, существуют специфические способы ОС для создания областей совместно используемой памяти, к которым могут обращаться несколько процессов.
переполнение стека само по себе не приводит к сбою, оно приводит к тому, что значения памяти записываются в местах, которые могут содержать другие значения, что приводит к его повреждению. Работа с поврежденной памятью вызывает сбои. Когда ваш процесс получает доступ к неотображенной памяти (см. Примечание ниже), происходит сбой не только потока, но и всего процесса. Это не повлияет на другие процессы, поскольку их области памяти изолированы. (Это не так в старых операционных системах, таких как Windows 95, где все процессы совместно используют одно и то же пространство памяти).
В C ++ объекты, размещенные в стеке, создаются при входе в блок и уничтожаются при выходе из блока. Хотя фактическое пространство в стеке может быть распределено менее точно, но строительство и разрушение будут происходить именно в этих точках.
Указатель стека в процессах x86 может быть произвольно изменен. Обычно компиляторы генерируют код, который просто добавляет объем пространства к указателю стека, а затем устанавливает память для значений в стеке, вместо того чтобы выполнять кучу операций push.
Стеки и куча процесса все живут в одном и том же пространстве памяти.
Обзор того, как организована память, может быть полезным:
delete
значение, на которое он указывает, но иначе невозможно очистить эту память. Деструкторы для глобальных переменных будут вызываться автоматически при выходе из приложения (ну, может быть, не с SIGTERM)