Windows также добивается, чтобы размер и базовый адрес зарезервированного региона адресного пространства всегда был кратен размеру страницы. Например, системы типа x86 используют страницы размером 4 Кб, и, если вы попытаетесь зарезервировать 18 Кб памяти, на самом деле будет зарезервировано 20 Кб. A если вы укажете базовый адрес 3 Кб для 18-килобайтного региона, то на самом деле будет зарезервировано 24 Кб.

Разделяемая память и проецируемые файлы

Как и большинство современных операционных систем, Windows поддерживает механизм разделения памяти. Разделяемой (shared memory) называется память, видимая более чем одному процессу или присутствующая в виртуальном адресном пространстве более чем одного процесса. Например, если два процесса используют одну и ту же DLL, есть смысл загрузить ее код в физическую память лишь один раз и сделать ее доступной всем процессам, проецирующим эту DLL (рис. 7–1).

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

Для реализации разделяемой памяти используются примитивы диспетчера памяти, объекты «раздел», которые в Windows API называются объектами «проекция файла» (file mapping objects). Внутренняя структура и реализация этих объектов описывается в разделе «Объекты-разделы» далее в этой главе.

Этот фундаментальный примитив диспетчера памяти применяется для проецирования виртуальных адресов в основной памяти, страничном файле или любых других файлах, к которым приложение хочет обращаться так, будто они находятся в памяти. Раздел может быть открыт как одним процессом, так и несколькими; иначе говоря, объекты «раздел» вовсе не обязательно представляют разделяемую память.

Объект «раздел» может быть связан с открытым файлом на диске (который в этом случае называется проецируемым) или с переданной памятью (для ее разделения). Разделы, проецируемые на переданную память, называются разделами, поддерживаемыми страничными файлами (page file backed sections), так как при нехватке памяти их страницы перемещаются в страничный файл. (Однако Windows может работать без страничного файла, и тогда эти разделы «поддерживаются» физической памятью.) Разделяемые переданные страницы, как и любые другие страницы, видимые в пользовательском режиме (например, закрытые переданные страницы), всегда обнуляются при первом обращении к ним.

Для создания объекта «раздел» используется Windows-функция Create-FileMapping, которой передается описатель проецируемого файла (или INVALID_HANDLE_VALUE в случае раздела, поддерживаемого страничным файлом), а также необязательные имя и дескриптор защиты. Если разделу присвоено имя, его может открыть другой процесс вызовом OpenFileMapping. Кроме того, вы можете предоставить доступ к объектам «раздел» через наследование описателей (определив при открытии или создании описателя, что он является наследуемым) или их дублирование (с помощью Duplicate-Handle). Драйверы также могут манипулировать объектами «раздел» через функции ZwOpenSection, ZwMapViewOfSection и ZwUnmapViewOfSection.

Объект «раздел» может ссылаться на файлы, длина которых намного превышает размер адресного пространства процесса. (Если раздел поддерживается страничным файлом, в нем должно быть достаточно места для размещения всего раздела.) Используя очень большой объект «раздел», процесс может проецировать лишь необходимую ему часть этого объекта, которая называется представлением (view) и создается вызовом функции MapViewOfFiIe с указанием проецируемого диапазона. Это позволяет процессам экономить адресное пространство, так как на память проецируется только представление объекта «раздел».

Windows-приложения могут использовать проецирование файлов для упрощения ввода-вывода в файлы на диске, просто делая их доступными в своем адресном пространстве. Приложения — не единственные потребители объектов «раздел»: загрузчик образов использует их для проецирования в память исполняемых образов, DLL и драйверов устройств, а диспетчер кэша — для доступа к данным кэшируемых файлов. (Об интеграции диспетчера кэша с диспетчером памяти см. в главе 11.) O реализации разделов совместно используемой памяти мы расскажем потом.


Логин
Пароль
Запомнить меня