Почему Windows резервирует 1 ГБ (или 2 ГБ) для своего системного адресного пространства? - PullRequest
19 голосов
/ 12 июля 2009

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

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

У меня вопрос ПОЧЕМУ?

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

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

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

Ответы [ 6 ]

22 голосов
/ 12 июля 2009

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

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

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

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


Времена изменились с тех пор, как этот вопрос был первоначально задан и получен ответ: 64-битные операционные системы сейчас гораздо более распространены. В текущих ОС на x86-64 виртуальные адреса от 0 до 2 47 -1 (0-128 ТБ) разрешены для пользовательских программ, в то время как ядро ​​постоянно находится в виртуальных адресах от 2 47 & times; (2 17 -1) до 2 64 -1 (или от -2 47 до -1, если вы рассматриваете адреса как целые числа со знаком).

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

8 голосов
/ 12 июля 2009

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

3 голосов
/ 12 июля 2009

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

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

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

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

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

2 голосов
/ 12 июля 2009

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

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

1 голос
/ 12 июля 2009

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

Но вот лучшее обсуждение .

0 голосов
/ 12 июля 2009

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...