Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
385
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

элемента поменялось на 2 143 289 344 (2 Гб за вычетом 4 Мб). Разница в 4 Мб возникает из-за того, что Windows 98 блокирует нижний раздел от 0x00000000 до 0x003FFFFF (размером в 4 Мб).

И, наконец, dwAvailVirtual (показываемый как AvailVirtual) — единственный элемент структуры, специфичный для конкретного процесса, вызывающего GlobalMemoryStatus (остальные элементы относятся исключительно к самой системе и не зависят от того, какой именно процесс вызывает эту функцию). При подсчете значения dwAvaiWirtual функция суммирует размеры вссх свободных регионов в адресном пространстве вы зывающего процесса. В данном случае его значение говорит о том, что в распоряже нии программы VMStat имеется 2 136 846 336 байтов свободного адресного простран ства. Вычтя из значения dwTotalVirtual величину dwAvailVirtual, Вы получите 10 506 240 байтов

— такой объем памяти VMStat зарезервировала в своем виртуальном адресном

пространстве Отдельного элемента, который сообщал бы количество физической памяти, используемой процессом в данный момент, не предусмотрено

Определение состояния адресного пространства

В Windows имеется функция, позволяющая запрашивать определенную информацию об участке памяти по заданному адресу (в пределах адресного пространства вызыва ющего процесса): размер, тип памяти и атрибуты защиты. В частности, с ее помощью программа VMMap (ее листинг см. на рис. 14-4) выводит карты виртуальной памяти, с которыми мы познакомились в главе 13Вот эта функция:

DWORD VirtualQuery( LPCVOID pvAddress, PMEMORY_BASIC_INFORMATION pmbi, DWORD dwLength);

Парная ей функция, VirtualQueryEx, сообщает ту же информацию о памяти, но в другом процессе:

DWORD VirtualQueryEx( HANDLE hProcess, LPCVOID pvAddress,

PMEMORY_BASIC_INFORMATION pmbi, DWORD dwLength);

Эти функции идентичны с тем исключением, что VirtualQueryEx принимает опи сатель процесса, об адресном пространстве которого Вы хотите получить информа цию Чаще всего функцией VirtualQueryEx пользуются отладчики и системные утили ты — остальные приложения обращаются к VirtitalQuery. При вызове VirtualQitery(Ex) параметр pvAddress

должен содержать адрес виртуальной памяти, о которой Вы хо тите получить информацию Параметр ртbi — это адрес структуры MEMORY_BA SIC_INFORMATION, которую надо создать перед вызовом функции. Данная структура определена в файле

WinNT.h так

typedef struct _MFMORY_BASIC_INFORMATION

{

PVOID BaseAddress;

PVOID AllocationBase;

DWORD AllocationProtect;

SIZE_T RegionSize;

DWORO State;

DWORD Protect;

DWORD Type;

} MEMORY_BASIC_INFORMATION, PMEMORY_BASIC_INFORMATION;

Параметр dwLength задает размер структуры MEMORY_BASIC_INFORMATION. Фун кция VirtualQuery(Ex) возвращает число байтов, скопированных в буфер.

Используя адрес, указанный Вами в параметре pvAddress, функция VirtualQuery(Ex) заполняет структуру информацией о диапазоне смежных страниц, имеющих одина ковые состояние, атрибуты защиты и тип. Описание элементов структуры приведено в таблице ниже

Элемент

Описание

 

 

BaseAddress

Сообщает то же значение, что и параметр pvAddress, но округленное до ближайшего меньшею адреса,

 

кратного размеру страницы

 

 

AllocationBase

Идентифицирует базовый адрес региона, включающего в себя адрес, указанный в параметре pvAddress

 

 

AllocationProtect

Идентифицирует атрибут защиты, присвоенный региону при его резервировании

 

 

RegionSize

Сообщаем суммарный размер (в байтах) группы страниц, которые на чинаются с базового адреса

 

BaseAddress и имеют тс же атрибуты защи ты, состояние и тип, что и страница, расположенная по адресу,

 

укачан ному в параметре pvAddress

 

 

State

Сообщает состояние (MEM_FRFF, MFM_RFSFRVE или MEM_COMMIT) всех смежных страниц, которые

 

имеют те же атрибуты защиты, состо яние и тип, что и страница, расположенная по адресу, указанному в

 

параметре pvAddress.

 

При MEM_FREE элементы AllocationBase, AllocationProtect, Protect и Туре содержат неопределенные

 

значения, а при MEM_RESERVE неопреде ленное значение содержит элемент Protect.

Protect

Идентифицирует атрибут защиты (PAGE *) всех смежных страниц, ко торые имеют те же трибуты

 

защиты, состояние и тип, что и страница, расположенная по адресу, указанному в параметре pvAddress

 

 

Type

Идентифицируем тип физической памяти (MEM_IMAGE, MEM_MAPPED или MEM PRIVATE),

 

связанной с группой смежных страниц, которые имеют те же атрибуты защиты, состояние и тип, что и

 

страница, рас положенная по адресу, указанному в пара метре pvAddress В Windows 98 этот элемент всегда

 

дает MFM_PRIVATE

 

 

Функция VMQuery

Начиная изучать архитектуру памяти в Windows, я пользовался функцией VirtualQuery как «поводырем». Если Вы читали первое издание моей книги, то заметите, что про грамма VMMap была гораздо проще ее нынешней версии, представленной в следую щем разделе. Прежняя была построена на очень простом цикле, из которого перио дически вызывалась функция VirtualQuery, и для каждого вызова я формировал одпу строку, содержавшую элементы структуры MEMORY_BASIC__INFORMATION. Изучая полученные дампы и сверяясь с документацией из SDK (в то время весьма неудачной), я пытался разобраться в архитектуре подсистемы управления памятью. Что ж, с тех пор я многому научился и теперь знаю, что функция VirtualQuery и структура MEMO RY_BASIC_INFORMATION не дают полной картины

Проблема в том, чю в MEMORY_BASIC_INFORMATION возвращается отнюдь не вся информация, имеющаяся в распоряжении системы. Если Вам нужны простейшие дан ные о состоянии памяти по конкретному адресу, VirtualQuery действительно незаме нима. Она отлично работает, если Вас интересует, передана ли по этому адресу фи зическая память и доступен ли он для операций чтения или записи. Но попробуйте e ее помощью узнать общий размер зарезервированного региона и количество блоков в нем или выяснить, не содержит ли этот регион стек потока, — ничего не выйдет

Чтобы получать более полную информацию о памяти, я создал собственную фун кцию и назвал ее VMQuery.

BOOL VMQuery( HANDLE hProcess, PVOID pvAddress, PVMQUERY pVMQ);

По аналогии с VirtualQueryEx она принимает в hProcess описатель процесса, в pvAddress

адрес памяти, а в pVMQ — указатель на структуру, заполняемую самой функцией. Структура VMQUERY (тоже определенная мной) представляет собой вот что.

typedef struct

{

//информация о регионе

PVOID pvRgnBaseAddress; DWORD dwRgnProtection;

//PAGE_*

SIZE_T RgnSize;

DWORD dwRgnStorage;

//MEM_* Free. Irnage, Mapped, Private DWORD dwRgnBlocks;

DWORD dwRgnGuardBlks; // если > 0, регион содержит стек потока

BOOL tRqnlsAStack; // TRUE, если регион содержит стек потока

//информация о блоке

PVOID pvBlkBaseAddress;

DWORD dwBlkProtection;

// PAGE_*

SIZE_T BlkSize;

DWORD dwBlkStorage;

//MEM_* Free, Reserve, Image, Mapped, Private

}VMQUERY, *PVMQUERY;

Спервого взгляда заметно, что моя структура VMQUERY содержит куда больше информации, чем MEMORY_BASIC_INFORMATION Она разбита (условно, конечно) на две части: в одной — информация и регионе, в другой — информация о блоке (адрес которого указан в параметре pvAddress). Элементы этой структуры описываются в следующейтаблице.

Элемент

Описание

pvRgnBaseAddress

Идентифицирует базовый адрес региона виртуального адресного про странства, включающего

 

адрес, указанный в параметре pvAddress

 

 

dwRgnProtection

Сообщает атрибут защиты, присвоенный региону при его резервиро вании.

 

 

RgnSize

Указывает размер (в байтах) зарезернириванного о региона.

 

 

dwRgnStorage

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

 

MEM_FREE, MEM_IMAGE, MEM_MAPPED или MEM PRIVATE. Поскольку Windows 98 не

 

различает типы памяти, в этой операционной системе данный элемент содержит либо

 

MEM_FREE, либо MEM_PRIVATE

 

 

dwRgnBlocks

Содержит значение — число блоков в указанном регионе

 

 

dwRgnGuardBlks

Указывает число блоков с установленным флагом атрибутов защиты PAGE GUARD. Обычно это

 

значение либо 0, либо 1. Если оно равно 1, то регион скорее всего зарезервирован под стек

 

потока В Windows 98 этот элемент всегда равен 0

fRgnIsAStack

Сообщает, есть ли в данном регионе стек потока Результат определя ется на основе взвешенной

 

оценки, так как невозможно дать стопро центной гарантии тому, что в регионе содержится стек.

 

 

pvBlkBaseAddress

Идентифицирует базовый адрес блока, включающего адрес, указанный в параметре pvAddress,

 

 

dwBlkProtection

Идентифицирует атрибут защиты блока, включающего адрес, указан ный в параметре pvAddress.

 

 

BlkSize

Содержит значение — размер блока (в байтах), включающего адрес, указанный в параметре

 

pvAddress.

 

 

dwBlkStorage

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

 

Принимает одно из значений: MEM FREE, MEM_RESERVE, MEM_IMAGE, MEM_MAPPED или

 

MEM_PRIVATE. В Windows 98 этот элемент никогда не содержит значения MEM IMAGE и

 

MEM MAPPED

 

 

Чтобы получить всю эту информацию, VMQuery, естественно, приходится выпол нять гораздо болыше операций (в том числе многократно вызывать VirtualQueryEx), а потому она работает значительно медленнее VirtualQueryEx. Так что Вы должны все тщательно взвесить, прежде чем остановить свой выбор па одной из этих функций Если Вам не нужна дополнительная информация, возвращаемая VMQuery, используй те VirtualQuery

или VirtualQueryEx.

Листинг файла VMQuerycpp (рис. 14-3) показывает, как я получаю и обрабатываю данные, необходимые для инициализации элементов структуры VMQUERY. (Файлы VMQuery.cpp и VMQueryh содержатся в каталоге 14-VMMap на компакт-диске, прила гаемом к книге.)

Чтобы не объяснять подробности обработки данных «на пальцах», я снабдил тексты программ массой комментариев, вольно разбросанных но всему коду.

Программа-пример VMMap

Эта программа, «14 VMMap.exe» (см. листинг на рис 14-4), просматривает свое адрес ное пространство и показывает содержащиеся в нем регионы и блоки, присутствую щие в регионах Файлы исходного кода и ресурсов этой программы находятся в ка талоге 14VMMap па компакт-диске, прилагаемом к книге. После запуска VMMap на

экране появляется следующее окно.

Карты виртуальной памяти, представленные в главе 13 в таблицах 13-2, 13-3 и 13-4, созданы с помощью именно этой программы

Каждый злемент в списке — результат вызова моей функции VMQuery. Основний цикл программы VMMap (в функции Refresb) выглядит так:

BOOL fOk = TRUE;

PVOID pvAddress = NULL;

...

while (fOk)

{

VMQUERY vmq;

fOk = VMQuery(hProcess, pvAddress, &vmq);

if (fOk)

{

//формируем строку для вывида на экран

//и добавляем ее в окно списка

TCHAR szLine[1024];

ConstructRgnInfoLine(hProcess. &vmq, szLine, sizeof(szLine});

LisTBox_AddString(hwndLB, szLine);

if (fExpandRegions)

{

for (DWORD dwBlock = 0; f0k && (dwBlock < vmq.dwRgnBlocks); dwBlock++)

{

ConstructBlkInfoL ine(&vmq, szLine, sizeof(szLine)); ListBox_AddString (hwndLB, szLine);

// получаем адрес следующего региона

pvAddress = ((PBYTE) pvAddress + vmq BlkSize);

if (dwBlock < vmq dwRgnBlocks - 1)

{

//

нельз

я

запра

шиват

ь

инфор

мацию

о

памят и за после дним блоко

м

fOk = VMQue ry(li Proce ss, pvAdd ress, &vmq)

;

}

}

}

// получаем адрес следующего региона