Как один и тот же виртуальный адрес для разных процессов сопоставляется с разными физическими адресами
Я взял курс о дизайне и концепции операционной системы, и теперь я пытаюсь тщательно изучить ядро Linux. У меня есть вопрос, от которого я не могу избавиться. В современных операционных системах каждый процесс имеет собственное виртуальное адресное пространство (VAS) (например, от 0 до 2^32-1 в 32-разрядных системах). Это дает много преимуществ. Но в реализации я запутался в некоторых моментах. Позвольте мне объяснить это на примере:
предположим, у нас есть два процесса p1, p2;
p1 и p2 имеют свои собственные вазы. Адрес 0x023f4a54
сопоставляется с различными физическими адресами (PA), как это может быть? Как делается этот перевод таким образом. Я имею в виду, что знаю механизм перевода, но я не могу понять, что один и тот же адрес сопоставляется с другим физическим адресом, когда речь идет о адресном пространстве разных процессов.
0x023f4a54 in p1's VAS => PA 0x12321321
0x023f4a54 in p2's VAS => PA 0x23af2341 # (random addresses)
6 ответов
процессор, предоставляющий виртуальную память, позволяет настроить сопоставление адресов памяти по мере того , как процессор видит его с адресами физической памяти, как правило, это делается устройством harware под названием MMU.
ядро ОС может запрограммировать этот MMU, как правило, не до отдельных адресов, а в единицах страниц (4096 байт является общим). Это означает, что MMU можно запрограммировать на перевод, например, виртуальных адресов 0x1000-0x2000 для перевода на физический адрес 0x20000-0x21000.
ОС сохраняет один набор этих сопоставлений для каждого процесса, и прежде чем планировать процесс для запуска, он загружает это сопоставление в MMU, прежде чем переключать управление обратно в процесс. Это позволяет использовать различные сопоставления для различных процессов, и ничто не мешает этим сопоставлениям сопоставлять один и тот же виртуальный адрес с другим физическим адресом.
все это прозрачно, насколько это касается программы, она просто выполняет инструкции на CPU, и как CPU был установлен в режим виртуальной памяти (режим выгрузки), каждый доступ к памяти переводится MMU, прежде чем он выходит на физической шине в память.
фактические детали реализации сложны, но вот некоторые ссылки, которые могут предоставить больше проницательность;
ваш вопрос путает виртуальный адрес с использованием адреса в качестве способа идентификации, поэтому первым шагом к пониманию является разделение понятий.
рабочим примером является функция библиотеки времени выполнения C sprintf()
. При правильном объявлении и вызове он включается в программу как модуль общего объекта вместе со всеми необходимыми подфункциями. Адрес sprintf
варьируется от программы к программе, потому что библиотека загружается в свободного адреса. Для простого Привет, мир программа, sprintf может быть загружен по адресу 0x101000. Для сложной программы, которая вычисляет налоги, она может быть загружена в 0x763f8000 (из-за всей дурацкой логики, которую содержит основная программа, идет перед библиотеками, на которые она ссылается). С точки зрения системы общая библиотека загружается в память только в одном месте, но окно адреса (диапазон адресов), которое каждый процесс видит, что память уникальна для этого исполняемого файла.
Of конечно, это еще больше осложняется некоторыми особенностями Улучшенная Безопасность Linux (SELinux) который рандомизирует адреса, по которым различные разделы программы загружаются в память, включая отображение общей библиотеки.
--- уточнение --- Как кто-то правильно указывает, виртуальное сопоставление адресов каждого процесса специфично для каждого процесса, в отличие от его набора файловых дескрипторов, соединений сокетов, родительских и дочерних процессов и т. д. То есть, Р1 может адрес карты 0x1000 к физическому 0x710000 в то время как P2 maps адрес 0x1000 к ошибке страницы, а p3 сопоставляется с некоторой общей библиотекой в физическом 0x9f32a000. Виртуальное сопоставление адресов тщательно контролируется операционной системой, возможно, для предоставления таких функций, как обмен и подкачка, но также для предоставления таких функций, как общий код и данные, а также межпроцессные общие данные.
существует две важные структуры данных, связанные с подкачкой: таблица страниц и TLB. ОС поддерживает различные таблицы страниц для каждого процесса. TLB-это просто кэш таблицы страниц.
теперь разные процессоры, ну, разные. x86 обращается к таблицам страниц напрямую, используя специальный регистр CR3, который указывает на используемую таблицу страниц. Процессоры MIPS ничего не знают о таблице страниц, поэтому ОС должна работать непосредственно с TLB.
некоторые процессоры (e.g: MIPS) храните идентификатор в TLB, чтобы отделить разные процессы друг от друга, поэтому ОС может просто изменить регистр управления при выполнении контекстного переключателя (если ему не нужно повторно использовать идентификатор). Другие процессоры требуют полного сброса TLB в каждом переключателе контекста. Таким образом, в основном, ОС необходимо изменить некоторые управляющие регистры и, возможно, необходимо очистить TLB (сделать TLB flush), чтобы виртуальные адреса из разных процессов отображались на любые физические адреса, которые они должны.
Спасибо за все ответы. На самом деле я не знаю, как один и тот же виртуальный адрес разных процессов не конфликтует с физическим корреспондентом друг друга. Я нашел ответ в ссылке ниже, каждый процесс имеет свою таблицу страниц.
это сопоставление (виртуальный адрес с физическим адресом) обрабатывается ОС и MMU (см. ответ @nos); точка этой абстракции так p1 "думает", что это доступ 0x023f4a54
когда на самом деле это доступ 0x12321321
.
Если вы вернетесь к своему классу о том, как программы работают на уровне машинного кода, p1 будет ожидать, что какая-то переменная / функция/что-то будет в том же месте (например,0x023f4a54
) каждый раз, когда он загружается. Физическое сопоставление ОС с виртуальным адресом обеспечивает это абстракция. На самом деле, он не всегда будет загружен до одного и того же физическая адрес, но ваша программа не заботится, пока она находится в том же виртуальный адрес.
Я думаю, что важно иметь в виду, что каждый процесс имеет свой собственный набор таблиц страниц. Мне было трудно понять это, когда я думал, что есть одна таблица страниц для всей системы.
когда конкретный процесс ссылается на свою таблицу страниц и пытается получить доступ к странице, которая еще не была сопоставлена с фреймом страницы, ОС выделяет другой кусок физической памяти для этого конкретного процесса и сопоставляет его с виртуальным адресом.