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

• Программистам и таким инструментам, как компилятор и компоновщик, не нужно знать о физическом размещении программы в оперативной памяти.

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

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

6.5. Стек и стековые фреймы

По мере вызова функций и возврата из них стек расширяется и сжимается. В Linux на архитектуре x86-32 (и в большинстве других реализаций Linux и UNIX) стек располагается в верхней части памяти и растет вниз (по направлению к куче). Текущая вершина стека отслеживается в специально предназначенном для этого регистре — указателе стека. Как только вызывается функция, стеку выделяется еще один фрейм, который удаляется, как только происходит возврат из функции.

Хотя стек растет вниз, мы все равно называем растущий край стека вершиной, поскольку, абстрактно говоря, он таковым и является. Фактическое направление роста относится к подробностям аппаратной реализации. В одной из реализаций Linux, HP PA-RISC, используется стек, растущий вверх.

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

Иногда применяется выражение «пользовательский стек» — это позволяет отличить рассматриваемый здесь стек от стека ядра. Стек ядра — поддерживаемая в памяти ядра область, выделяемая каждому процессу, которая используется в качестве стека для выполнения функций, вызываемых внутри системного вызова в ходе его работы. (Ядро не может применять для этой цели пользовательский стек, поскольку тот размещается в незащищенной пользовательской памяти.)

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

• Аргументы функции и локальные переменные. В языке C они упоминаются как автоматические переменные, поскольку при вызове функции создаются в автоматическом режиме. Исчезают они также автоматически, когда происходит возврат из функции (поскольку исчезает фрейм стека). В этом основное семантическое отличие автоматических переменных от статических (глобальных): последние существуют постоянно, независимо от выполнения функций.

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

Поскольку функции способны вызывать друг друга, в стеке может быть несколько фреймов. (Если функция рекурсивно вызывает саму себя, то для этой функции в стеке будет несколько фреймов.) Если вспомнить листинг 6.1, то в ходе выполнения функции square() в стеке будут содержаться фреймы, показанные на рис. 6.3.

Рис. 6.3.Пример стека процесса

6.6. Аргументы командной строки (argc, argv)
Перейти на страницу:

Похожие книги