Резервирование региона в адресном пространстве
Для этого предназначена функция VirtualAlloc
PVOID VirtualAlloc( PVOID pvAddress, SIZE_T dwSize, DWORD fdwAllocationType, DWORD fdwProtecf);
В первом параметров, pvAddress, содержится адрес памяти, указывающий, где имен но система должна за резервировать адресное пространство Обычно в этом параметре передают NULL, тем самым сообщая функции VirtualAlloc, что система, ведущая учет свободных областей, должна зарезервировать регион там, где, по ее мнению, будет лучше Поэтому нет никаких гарантий, что система станет резервировать регионы, начиная с нижних адресов или, Haoбopoт, с верхних Однако с помощью флага MEM_ TOP_DOWN (о нем речь впереди) Вы можете сказать свое веское слово
Для большинства программистов возможность выбора конкретного адреса резер вируемого региона — нечто совершенно новое Вспомните, как это делалось раньше операционная система просто находила подходящий по размеру блок памяти, выде ляла этот блок и возвращала его адрес Но поскольку каждый процесс владеет соб ственным адресным пространством, у Вас появляется возможность указывать опера ционной системе желательный базовый адрес резервируемого региона
Допустим, нужно выделить регион, начиная с «отметки» 50 Мб в адресном про странстве процесса. Тогда параметр pvAdress должен быть равен 52 428 800 (50 * 1024 * 1024). Если по этому адресу можно разместить регион требуемого размера, систе ма зарезервирует его и вернет соответствующий адрес. Если же по этому адресу сво бодного пространства недостаточно или просто нет, система не удовлетворит зап рос, и функция VirtualAlloc вернет NULL Адрес, передаваемый pvAdress, должен ук ладываться в границы раздела пользовательского режима Вашего процесса, так как иначе VirtualAlloc потерпит неудачу и вернет NULL.
Как я уже говорил в главе 13, регионы всегда резервируются с учетом грануляр ности выделения памяти (64 Кб для существующих реализаций Windows). Поэтому, если Вы попытаетесь зарезервировать регион по адресу 19668992 (300 x 65 536 + 8192), система округлит этот адрес до ближайшего меньшего числа, кратного 64 Кб, и на самом делс зарезервирует регион по адресу 19 660 800 (300 x 65 536).
Если VirtualAlloc в состоянии удовлетворить запрос, она возвращает базовый ад рес зарезервированного региона. Если параметр pvAddress содержал конкретный ад рес, функция возвращает этот адрес, округленный при необходимости до меньшей величины, кратной б4 Кб.
Второй параметр функции VirtualAlloc — dwSize — указывает размер резервируе мого региона в байтах. Поскольку система резервирует регионы только порциями, кратными размеру страницы, используемой данным процессором, то попытка заре зервировать, скажем, 62 Кб даст регион размером 64 Кб (если размер страницы со ставляет 4, 8 или l6 Кб).
Третий параметр ,fdwAllocationType, сообщает системе, что именно Вы хотите сде лать: зарезервировать регион или передать физическую память. (Такое разграниче ние необходимо, поскольку VirtualAlloc позволяет не только резервировать регионы, но и передавать им физическую память.) Поэтому, чтобы зарезервировать регион адресного пространства, в этом параметре нужно передать идентификатор MEM_RE SERVE.
Если Вы хотите зарезервировать регион и не собираетесь освобождать его в бли жяйшее время, попробуйте выделить его в диапазоне самых старших — насколько это возможно - адресов. Тогда регион не окажется где-нибудь в середине адресного про странства процесса, что позволит не допустить вполне вероятной фрагментации этого пространства. Чтобы зарезервировать регион по самым старшим адресам, при вызо ве функции VirtualAlloc в параметре pvAddress передайте NULL, а в параметреь fdwAlloc- cationType — флаг MEM_RESERVE, скомбинированный с флагом MEM_TOP_DOWN.
NOTE:
В Windows 98 флаг MEM_TOP_DOWN игнорируется.
Последний параметр fdwProtect, указывает атрибут зущиты, присваиваемый реги ону Заметьте, что атрибут защиты, связанный с регионом, не влияет на переданную память, отображаемую на этот регион Но если ему не передана физическая память, то — какой бы атрибут защиты у него ни был — любая попытка обращения по одно му из адресов в этом диапазоне приведет к нарушению доступа для данного потока.
Резервируя регион, присваивайте сму тот атрибут защиты, который будет чаще всего использоваться с памятью, передаваемой региону. Скажем, если Вы собираетесь передать региону физическую память с атрибутом защиты PAGEREADWR!TE (этот атрибут самый распространенный), то и резервировать его следует с тем же атрибу том, Система работает эффективнее, когда атрибут защиты региона совпадает с ат рибутом защиты передаваемой памяти.
Вы можете использовать любой из следующих атрибутов защиты: PAGE_NOACCESS, PAGE_READWRITE, PAGE_READONLY, PAGE_EXECUTE, PAGE_EXECUTE_READ или PAGE_ EXECUTE_READWRITE. Но указывать атрибуты PAGE_WRITECOPY или PAGE_EXECUTE_ WRITECOPY нельзя: иначе функция VirtualAtloc не зарезервирует регион и вернет NULL Кроме того, при резервировании региона флаги PAGE_GUARD, PAGE_WRITECOMBINE или PAGE_NOCACHE применять тоже нельзя — они присваиваются только передава емой памяти.
NOTE:
Windows 98 поддерживаетлишь атрибугы защиты PAGE_NOACCESS, PAGE_READONLY и PAGE_READWRITE Попытка резервирования региона с атрибутом PAGE_EXECUTE или PAGE_EXECUTE_READ дает регион с атрибутом PAGE_READONLY. А указав PAGE_EXECUTE_READWRITE, Вы получите регион с атрибутом PAGE_READWRITE.