Другие функции управления кучами
Кроме уже упомянутых, в Windows есть еще несколько функций, предназначенных для управления кучами. В этом рязделс я вкратце расскажу Вам о них.
ToolHelp-функции (упомянутые в конце главы 4) дают возможность перечислять кучи процесса, а также выделенные внутри них блоки памяти. За более подробной информацией я отсылаю Вас к документации Plarform SDK: ищите разделы по функ циям Heap32Ftrst, Heap32Next, Heap32ListFirst и Heap32ListNext. Самое ценное в этих функциях то, что они доступны как в Windows 98, так и в Windows 2000. Прочие функ ции, о которых пойдет речь в этом разделе, есть только в Windows 2000.
В адресном пространстве процесса может быть несколько куч, и функция GetPro cessHeaps позволяет получить их описатели "одним махом":
DWORD GetProcessHeaps( DWORD dwNumHeaps, PHANDLE pHeaps);
Предварительно Вы должны создать массив описателей, а затем вызвать функцию так, как показано ниже.
HANDLE hHeaps[25];
DWORD dwHeaps = GetProcessHeaps(25, hHeaps);
if (dwHeaps > 25)
{
// у процесса больше куч, чем мы ожидали
}
else
{
// элеметы от hHeaps[0] до hHeaps[dwHeaps - 1]
// идентифицируют существующие кучи
}
Имейте в виду, что описатель стандартной кучи процесса тоже включается в этот массив описателей, возвращаемый функцией GetProcessHeaps. Целостность кучи позволяет проверить функция HeapValidate:
BOOL HeapValidate( HANDLE hHeap, DWORD fdwFlags, LPCVOID pvMem);
Обычно ее вызывают, передавая в hHeap описатель кучи, в dwFlags — 0 (этот па раметр допускает еще флаг HEAP_NO_SERIALIZE), а в pvMem — NULL. Функция про сматривает все блоки в куче, чтобы убедиться в отсутствии поврежденных блоков. Чтобы она работала быстрее, в параметре pvMem можно передать адрес конкретного блока, Тогда функция проверит только этот блок.
Для объединения свободных блоков в куче, а также для возврата системе любых страниц памяти, на которых нет выделенных блоков, предназначена функция Heap Compact:
UINT HeapCompact( HANDLE hHeap, DWORD fdwFlags);
Обычно в параметре fdwFlags передают 0, но можно передать и HEAP_NO_SE RIALIZE
Следующие две функции — HeapLock и HeapUnlock — используются парно
BOOL Hpaplock(HANDLE hHeap);
BOOL HeapUnlock(HANDLE hHeap);
Они предназначены для синхронизации потоков После успешного вызова Heap Lock поток, который вьзывал эту функцию становится владельцем указанной кучи Ьсли другой поток обращается к этой куче, указывая тот же описатель кучи, система приостанавливает его выполнение до тех пор, пока куча не будет разблокирована вызовом HeapUnlock
Функции HeapAlloc, HeapSize, HeapFree и другие — все обращаются к HeapLock и HeapUnlock, чтобы обеспечить последовательный доступ к куче Самостоятельно вы зывать эти функции Вам вряд ли понадобится
Последняя функция, предназначенная для работы с кучами, — HeapWalk
BOOL HeapWalk( HANDLE hHeap, PPROCESS_HEAP_ENTRY pHoapEntry);
Она предназначена только для отладки и позволяет просматривать содержимое кучи Обычно ее вызывают по несколько paз, передавая адрес структуры PROCESS_ HEAP_ENTRY (Вы должны сами создать ее экземпляр и инициализировать)
typedef struct _PROCESS_HEAP_ENTRY
{
PVOID lpData;
DWORD cbData;
BYlE cbOverhead;
BYTE iRegionIndex;
WORD wFlags;
union
{
struct
{
HANDLE hMem; DWORD dwReserved[ 3 ];
} Block;
struct
{
DWORD dwCornmittedSize;
DWORD dwUnCommittedSize;
LPVOID lpFirstBlock;
LPVOID lpLastBlock;
} Region;
};
} PROCESS_HEAP_ENTRY, *LPPROCESS_HEAP_ENTRY, *PPROCESS_HEAP_ENTRY;
Прежде чем перечислять блоки в куче, присвойте NULL элементу lpData, и это заставит функцию HeapWalk инициализировать все элементы структуры Чтобы пе рейти к следующему блоку, вызовите HeapWalk еще раз, переддв сй тот же описатель кучи и адрес той же структуры PROCESS_HFAPENTRY Если HeapWalk вернет FALSE, значит, блоков в куче больше нет Подробное описание элементов структуры PRO CESS_HEAP_ENTRY см. в документации PlatformSDK
Обычно вызовы функции HeapWalk "обрамляют" вызовами HeapLock и HeapUnlock, чтобы посторонние потоки не портили картину, создавая или удаляя блоки в просматриваемой куче