Получение виртуальной памяти
У приложения есть две возможности заказать для себя страницы виртуальной памяти. Первая возможность заключается в резервировании заданного диапазона адресов в адресном пространстве приложения, вторая - в фактическом получении в пользование страниц виртуальной памяти, к которым можно выполнять обращение.
Процесс резервирования не отнимает много времени и не приводит к изменениям в файлах страниц. При резервировании приложение только отмечает область памяти, лежащую в заданном диапазоне адресов как зарезервированную.
Для чего может потребоваться резервирование диапазона адресов?
Например, при отображении файла, имеющего большие размеры, в память, приложение может зарезервировать область виртуальной памяти, имеющую размер, равный размеру файла (даже если файл занимает несколько сотен Мбайт). При этом гарантируется, что для адресации этой области памяти можно будет использовать сплошной диапазон адресов. Это удобно, если вы собираетесь работать с файлом, как с массивом, расположенным в оперативной памяти.
Если же приложение не резервирует, а получает страницы памяти для непосредственного использования, эти страницы физически создаются в виртуальной памяти и заполняются нулями. При этом может происходить запись в файлы страниц. Разумеется, такой процесс отнимает гораздо больше времени, чем резервирование.
Для того чтобы зарезервировать или получить в свое распоряжение некоторое количество страниц виртуальной памяти, приложение должно воспользоваться функцией 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 |
Память выделяется в области верхних адресов адресного пространства приложения |
Значение |
Разрешенный доступ |
PAGE_READWRITE |
Чтение и запись |
PAGE_READONLY |
Только чтение |
PAGE_EXECUTE |
Только исполнение программного кода |
PAGE_EXECUTE_READ |
Исполнение и чтение |
PAGE_EXECUTE_READWRITE |
Исполнение, чтение и запись |
PAGE_NOACCESS |
Запрещен любой вид доступа |
PAGE_GUARD |
Сигнализация доступа к старнице. Это значение можно использовать вместе с любыми другими, кроме PAGE_NOACCESS |
PAGE_NOCACHE |
Отмена кэширования для страницы памяти. Используется драйверами устройств. Это значение можно использовать вместе с любыми другими, кроме PAGE_NOACCESS |
С другой стороны, у вас есть возможность получения страниц, предназначенных только для хранения исполнимого кода. Если такие страницы отмечены как PAGE_EXECUTE, для них не разрешаются операции чтения и записи.
При необходимости зафиксировать обращение к той или иной странице приложение может отметить ее как PAGE_GUARD. Если произойдет попытка обращения к такой странице, возникнет исключение с кодом STATUS_GUARD_PAGE, после чего признак PAGE_GUARD будет автоматически сброшен.
В случае успешного завершения функция VirtualAlloc возвратит адрес зарезервированной или полученной области страниц. При ошибке будет возвращено значение NULL.
Приложение может вначале зарезервировать страницы, вызвав функцию VirtualAlloc с параметром MEM_RESERVE, а затем получить их в пользование, вызвав эту же функцию еще раз для полученной области памяти, но уже с параметром MEM_COMMIT.