Программирование для Windows NT

       

Получение виртуальной памяти


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

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

Для чего может потребоваться резервирование диапазона адресов?

Например, при отображении файла, имеющего большие размеры, в память, приложение может зарезервировать область виртуальной памяти, имеющую размер, равный размеру файла (даже если файл занимает несколько сотен Мбайт). При этом гарантируется, что для адресации этой области памяти можно будет использовать сплошной диапазон адресов. Это удобно, если вы собираетесь работать с файлом, как с массивом, расположенным в оперативной памяти.

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

Для того чтобы зарезервировать или получить в свое распоряжение некоторое количество страниц виртуальной памяти, приложение должно воспользоваться функцией VirtualAlloc, прототип которой представлен ниже:

LPVOID VirtualAlloc(

  LPVOID lpvAddress,        // адрес области

  DWORD  cbSize,            // размер области

  DWORD  fdwAllocationType, // способ получения памяти

  DWORD  fdwProtect);       // тип доступа

Параметры lpvAddress и cbSize задают, соответственно, начальный адрес и размер резервируемой либо получаемой в пользование области памяти. При резервировании адрес округляется до ближайшей границы блока размером 64 Кбайт. В остальных случаях адрес округляется до границы ближайшей страницы памяти.




Заметим, что параметр lpvAddress можно указать как NULL. При этом операционная система выберет начальный адрес самостоятельно.

Что же касается параметра cbSize, то он округляется до целого числа страниц. Поэтому если вы пытаетесь с помощью функции VirtualAlloc получить область памяти размером в один байт, вам будет выделена страница размером 4096 байт. Аналогично, при попытке получить блок памяти размером 4097 байт вы получите две страницы памяти общим размером 8192 байта. Как мы уже говорили, программный интерфейс системы управления виртуальной памятью не предназначен для работы с областями малого размера.

Для параметра fdwAllocationType вы можете использовать одно из следующих значений:

Значение

Описание

MEM_RESERVE

Функция VirtualAlloc выполняет резервирование диапазона адресов в адресном пространстве приложения

MEM_COMMIT

Выполняется выделение страниц памяти для непосредственной работы с ними. Выделенные страницы заполняются нулями

MEM_TOP_DOWN

Память выделяется в области верхних адресов адресного пространства приложения

С помощью параметра fdwProtect приложение может установить желаемй тип доступа для заказанных страниц. Можно использвать одно из следующих значений:

Значение

Разрешенный доступ

PAGE_READWRITE

Чтение и запись

PAGE_READONLY

Только чтение

PAGE_EXECUTE

Только исполнение программного кода

PAGE_EXECUTE_READ

Исполнение и чтение

PAGE_EXECUTE_READWRITE

Исполнение, чтение и запись

PAGE_NOACCESS

Запрещен любой вид доступа

PAGE_GUARD

Сигнализация доступа к старнице. Это значение можно использовать вместе с любыми другими, кроме PAGE_NOACCESS

PAGE_NOCACHE

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

Если страница отмечена как PAGE_READONLY, при попытке записи в нее возникает аппаратное прерывание защиты доступа (access violation). Эта страница также не может содержать исполнимый код. Попытка выполнения такого кода приведет к возникновению прерывания.

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

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

В случае успешного завершения функция VirtualAlloc возвратит адрес зарезервированной или полученной области страниц. При ошибке будет возвращено значение NULL.

Приложение может вначале зарезервировать страницы, вызвав функцию VirtualAlloc с параметром MEM_RESERVE, а затем получить их в пользование, вызвав эту же функцию еще раз для полученной области памяти, но уже с параметром MEM_COMMIT.


Содержание раздела