Как управляются, реализуются, распределяются кучи и стеки памяти?

В C/С++ мы можем хранить переменные, функции, функции-члены, экземпляры класса либо в стеке, либо в куче.

Как каждый реализован? Как это управляется (высокий уровень)? Gcc предопределяет кусок памяти, который будет использоваться для стека и кучи, а затем по запросу? Является ли исходная память из ОЗУ?

Можно ли назначить функцию в куче вместо стека?

Разъяснение

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

Ответ 1

Современные операционные системы не дают вам прямого доступа к аппаратной ОЗУ и вместо этого абстрактно его в так называемую виртуальную память, которая по требованию сопоставляется с ОЗУ. Каждому процессу обычно предоставляется собственная личная копия полного адресного пространства. Это позволяет ОС перемещать память процесса в ОЗУ во время выполнения или даже заменять его на диск. Это происходит прозрачно, то есть процесс не уведомляется о таком перемещении и не нуждается в коде для его обработки. (В некоторых приложениях реального времени могут быть использованы методы, позволяющие предотвратить их замену памяти).

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

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

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

В отличие от этого, память в куче выделяется с помощью new/delete, для которой компилятор вставляет код для запроса или выпуска памяти с использованием системной библиотеки.

Обратите внимание, что это упрощенное описание, чтобы дать вам представление о том, как работает распределение памяти.

Ответ 2

В основном куча не реализована компилятором, а вместо этого - библиотекой времени выполнения C. Очевидно, что этот код очень зависим от платформы. В Unix или Unix-подобных системах реализация обычно основывается на системном вызове sbrk/brk и выделяется больший объем памяти для уменьшения количества системных вызовов. Затем эта память управляется диспетчером памяти кучи. Если требуется больше памяти, выдается новый вызов sbrk. Текущий конечный адрес кучи можно получить с помощью sbrk (0), если вы заинтересованы в отладке подпрограмм управления кучей. Большинство менеджеров памяти не возвращают память в ОС в течение жизненного цикла процесса (библиотека gnu c runtime работает, если выполняются определенные ограничения).

Более подробное описание доступно в http://gee.cs.oswego.edu/dl/html/malloc.html.