Почему Windows резервирует 1 ГБ (или 2 Гб) для своего системного адресного пространства?

StackOverflow https://stackoverflow.com/questions/1115033

Вопрос

Общеизвестно, что приложения Windows обычно имеют 2 Гб частного адресного пространства в 32-разрядной системе.Это пространство может быть расширено до 3 Гб с помощью переключателя /3Gb.

Операционная система резервирует себе оставшиеся 4 ГБ.

Мой вопрос в ТОМ, ПОЧЕМУ?

Код, работающий в режиме ядра (т.е.код драйвера устройства) имеет свое собственное адресное пространство.Почему, помимо эксклюзивного адресного пространства в 4 ГБ, операционная система все еще хочет зарезервировать по 2 ГБ для каждого процесса пользовательского режима?

Я думал, причина в переходе между вызовом пользовательского режима и режима ядра.Например, вызов в NtWriteFile потребуется адрес для процедуры отправки ядра (следовательно, почему система резервирует 2 ГБ в каждом приложении).Но, используя SYSENTER, разве номера системной службы недостаточно для того, чтобы код режима ядра знал, какая функция / сервис вызывается?

Если бы вы могли разъяснить мне, почему для операционной системы так важно занимать 2 ГБ (или 1 ГБ) каждого процесса пользовательского режима.

Это было полезно?

Решение

Два разных пользовательских процесса имеют разные виртуальные адресные пространства.Поскольку сопоставления виртуального и физического адресов различны, TLB кэш становится недействительным при переключении контекстов с одного пользовательского процесса на другой.Это очень дорого, так как без адреса, уже кэшированного в TLB, любой доступ к памяти приведет к сбою и обходу ПТЭs.

Системные вызовы включают в себя два переключения контекста:пользователь→ ядро, а затем ядро→ пользователь.Чтобы ускорить это, обычно резервируется верхний 1 ГБ или 2 ГБ виртуального адресного пространства для использования ядром.Поскольку виртуальное адресное пространство не изменяется при этих переключениях контекста, сброс TLB не требуется.Это включается битом пользователя / супервизора в каждом PTE, который гарантирует, что память ядра доступна только в пространстве ядра;пользовательское пространство не имеет доступа, даже если таблица страниц одна и та же.

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

Linux на платформе x86 когда-то поддерживал режим, известный как "Разделение 4G / 4G".В этом режиме пользовательское пространство имеет полный доступ ко всему виртуальному адресному пространству объемом 4 ГБ, и ядро также имеет полное виртуальное адресное пространство объемом 4 ГБ.Стоимость, как упоминалось выше, заключается в том, что каждый системный вызов требует сброса TLB наряду с более сложными процедурами для копирования данных между пользовательской памятью и памятью ядра.Было подсчитано, что это приводит к снижению производительности до 30%.


Времена изменились с тех пор, как этот вопрос был первоначально задан и на него был дан ответ:64-разрядные операционные системы сейчас гораздо более распространены.В текущих операционных системах на x86-64 виртуальные адреса от 0 до 247-1 (0-128 ТБ) разрешены для пользовательских программ, в то время как ядро постоянно находится в пределах виртуальных адресов из 247×(217от -1) до 264-1 (или из -247 к -1, если вы рассматриваете адреса как целые числа со знаком).

Что произойдет, если вы запустите 32-разрядный исполняемый файл в 64-разрядной Windows?Можно подумать, что все виртуальные адреса от 0 до 232 (0-4GB) было бы легко доступно, но во избежание выявления ошибок в существующих программах 32-разрядные исполняемые файлы по-прежнему ограничены 0-2GB, если они не перекомпилированы с /LARGEADDRESSAWARE.Для тех, кто есть, они получают доступ к 0-4GB.(Это не новый флаг;то же самое применяется в 32-разрядных ядрах Windows, работающих с /3GB переключатель, который изменил разделение 2G / 2G user / kernel по умолчанию на 3G / 1G, хотя, конечно, 3-4 ГБ все равно будут вне зоны действия.)

Какие виды ошибок могут там быть?В качестве примера предположим, что вы реализуете быструю сортировку и у вас есть два указателя, a и b указывающий на начало и за конец массива.Если вы выберете середину в качестве стержня с (a+b)/2, это будет работать до тех пор, пока оба адреса меньше 2 ГБ, но если они оба выше, то при сложении произойдет переполнение целых чисел, и результат будет находиться за пределами массива.(Правильное выражение - это a+(b-a)/2.)

Кроме того, 32-разрядный Linux с разделением пользователя и ядра 3G / 1G по умолчанию исторически запускал программы со стеком, расположенным в диапазоне 2-3 ГБ, поэтому любые подобные ошибки программирования, скорее всего, были бы быстро устранены.64-разрядный Linux предоставляет 32-разрядным программам доступ к 0-4 ГБ.

Другие советы

У Рэймонда Чена был куча статей на эту тему.

Windows (как и любая ОС) - это намного больше, чем ядро + драйверы.

Ваше приложение полагается на множество служб операционной системы, которые существуют не только в пространстве ядра.Существует множество буферов, дескрипторов и всевозможных ресурсов, которые могут быть сопоставлены с собственным адресным пространством вашего процесса.Всякий раз, когда вы вызываете функцию Win32 API, которая возвращает, скажем, дескриптор окна или кисть, эти вещи должны быть размещены где-то в вашем процессе.Итак, часть Windows выполняется в ядре, да, другие части выполняются в своих собственных процессах пользовательского режима, а некоторые, к которым вашему приложению требуется прямой доступ, сопоставлены с вашим адресным пространством.Частично этого трудно избежать, но важным дополнительным фактором является производительность.Если каждый Вызов Win32 требовал переключения контекста, это сильно ударило бы по производительности.Если некоторые из них могут быть обработаны в пользовательском режиме, поскольку данные, на которые они опираются, уже сопоставлены с вашим адресным пространством, переключения контекста можно избежать, и вы сэкономите немало циклов процессора.

Таким образом, любая ОС нуждается некоторые объем выделенного адресного пространства.Я полагаю, что Linux по умолчанию устанавливает только 1 ГБ для ОС.

Причина, по которой MS остановилась на 2 ГБ с Windows, однажды была объяснена в блоге Рэймонда Чена.У меня нет ссылки, и я не могу вспомнить подробности, но решение было принято, потому что Windows NT изначально была ориентирована также на процессоры Alpha, а на Alpha была КАКАЯ-то ДЕЙСТВИТЕЛЬНО веская причина разделить 50/50.;)

Это было как-то связано с поддержкой Alpha как 32,так и 64-битного кода.:)

Код, работающий в режиме ядра (т.Е. код драйвера устройства), имеет собственное адресное пространство.

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

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

Но вот такой лучшая дискуссия.

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

Процессор Intel 8086 имел архитектуру памяти со смещением сегментов, обеспечивающую 20-разрядные адреса памяти и, следовательно, общий объем адресуемой физической памяти в 1 МБ.

В отличие от конкурирующих процессоров той эпохи , таких как Zilog Z80 , Intel 8086 имел только один адресное пространство который должен был содержать не только электронную память, но и все средства ввода-вывода данных с такими второстепенными периферийными устройствами, как клавиатура, последовательные порты, порты принтера и видеодисплеи.(Для сравнения, Zilog Z80 имел отдельное адресное пространство ввода-вывода с выделенными кодами операций сборки для доступа)

Необходимость выделить место для постоянно растущего диапазона периферийных расширений привела к первоначальному решению разделить адресное пространство на электронную память от 0 до 640 КБ, а "прочее" (ввод / вывод, ПЗУ, видеопамять и т.д.) - от 640 КБ до 1 МБ.

По мере роста и развития линейки x86, а вместе с ними и ПК, использовались аналогичные схемы, что привело к сегодняшнему разделению адресного пространства 4G на 2G.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top