Давайте возьмем в качестве примера 32-битные процессоры x86, немного упростив их для иллюстрации. Некоторые из перечисленных ниже являются немного неточными с целью предоставления концепции.
Инструкции, которые позволяют загружать и хранить память, будут принимать 32-битные аргументы. Таким образом, у вас есть пространство «32-битный адрес». Это означает, что вы можете "разговаривать" с объемом оперативной памяти 4 Гб или любым другим, что там происходит.
Виртуальная память позволяет нам сопоставить один адрес (логический или виртуальный адрес) с другим адресом (физическим, реальным адресом). Состояние по умолчанию - "сопоставление идентификаторов", где каждый логический адрес установлен на свой виртуальный адрес. Отображение происходит на уровне страницы размером 4KByte.
У вас есть 2 уровня исполнения - режим пользователя и режим ядра. Режим ядра должен быть идентифицирован, потому что он управляет системой и другими процессами.
В пользовательском режиме ядро отображает память, где ОЗУ начинается с адреса 0, и оно может достигать объема памяти, выделенного ему. Ядро контролирует отображение памяти всех процессов и определяет, какая память свободна и используется. Ядро может выбрать бесплатные 4K-байтовые страницы из любого места и расположить их так, чтобы они выглядели непрерывно в режиме пользовательского режима.
Механизм сопоставления может вызвать "сбой страницы", если страница пользовательского режима обращается к адресу, на котором страница недействительна. Если приложение пользовательского режима пытается получить доступ к большему количеству памяти, чем у него, оно попадет на "плохие" страницы и отключит исключение ядра. Затем ядро уничтожит его с ошибкой "Ошибка сегментации". API ядра позволяют приложению запрашивать больше памяти - ядро затем, если возможно, отобразит на нем некоторую свободную память и освободит ее, когда это будет сделано.
Поэтому, пока у вас есть 32-битное адресное пространство, вы не можете просто использовать все адреса в произвольном порядке в пользовательском процессе, если что-то не отображается там.
Теперь - если процесс бездействует, ядро может целенаправленно пометить некоторые страницы как "плохие", если оно определит, что к этим страницам не обращались в течение некоторого времени, и записать их на диск. Когда процесс проснется, он попытается получить доступ к этим плохим страницам и отключить исключение ядра. Вместо "segfaulting" ядро будет извлекать страницы с диска, вставлять их обратно в память (возможно, в другое физическое место, но сопоставленное с тем же логическим местом процесса), а затем возобновлять процесс. Вот как файл подкачки или подкачки вписывается в микс.
Как в современных ядрах Windows, так и в Linux имеется средство, называемое mmap
где этот механизм используется "специально", чтобы обеспечить доступ к файлу, как к части его памяти. Процесс пользовательского пространства может выбрать адрес, чтобы поместить его - и ядро будет реагировать на "ошибки", загружая или записывая нужные части файла на лету. Он использует этот механизм подкачки, чтобы разрешить это. В 64-разрядных системах с очень широким адресным пространством можно обращаться к очень большим файлам, как если бы они находились в памяти, что упрощает некоторые программы.