Обход списка куч
В следующем примере показано, как получить список кучи для текущего процесса. Он принимает snapshot кучи с помощью функции CreateToolhelp32Snapshot, а затем просматривает список с помощью функций Heap32ListFirst и Heap32ListNext. Для каждой кучи используются функции Heap32First и Heap32Next для обхода блоков кучи.
Примечание
Heap32First и Heap32Next неэффективны, особенно для больших кучи. Однако они полезны для запросов к другим процессам, где обычно требуется внедрить поток в другой процесс для сбора информации (эти API делают это за вас).
Во втором примере приведен эквивалентный, гораздо более эффективный вариант, в котором вместо Heap32First и Heap32Next используется HeapWalk. Обратите внимание, что HeapWalk можно использовать только для одного процесса.
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
int main( void )
{
HEAPLIST32 hl;
HANDLE hHeapSnap = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, GetCurrentProcessId());
hl.dwSize = sizeof(HEAPLIST32);
if ( hHeapSnap == INVALID_HANDLE_VALUE )
{
printf ("CreateToolhelp32Snapshot failed (%d)\n", GetLastError());
return 1;
}
if( Heap32ListFirst( hHeapSnap, &hl ) )
{
do
{
HEAPENTRY32 he;
ZeroMemory(&he, sizeof(HEAPENTRY32));
he.dwSize = sizeof(HEAPENTRY32);
if( Heap32First( &he, GetCurrentProcessId(), hl.th32HeapID ) )
{
printf( "\nHeap ID: %d\n", hl.th32HeapID );
do
{
printf( "Block size: %d\n", he.dwBlockSize );
he.dwSize = sizeof(HEAPENTRY32);
} while( Heap32Next(&he) );
}
hl.dwSize = sizeof(HEAPLIST32);
} while (Heap32ListNext( hHeapSnap, &hl ));
}
else printf ("Cannot list first heap (%d)\n", GetLastError());
CloseHandle(hHeapSnap);
return 0;
}
В следующем фрагменте кода функция HeapWalk используется для обхода кучи процесса, что позволяет получить идентичные выходные данные предыдущего примера, но гораздо эффективнее:
#include <windows.h>
#include <stdio.h>
int main( void )
{
DWORD heapIndex;
DWORD heapCount = 0;
PHANDLE heaps = NULL;
while (TRUE)
{
DWORD actualHeapCount = GetProcessHeaps(heapCount, heaps);
if (actualHeapCount <= heapCount)
{
break;
}
heapCount = actualHeapCount;
free(heaps);
heaps = (HANDLE*)malloc(heapCount * sizeof(HANDLE));
if (heaps == NULL)
{
printf("Unable to allocate memory for list of heaps\n");
return 1;
}
}
for (heapIndex = 0; heapIndex < heapCount; heapIndex++)
{
PROCESS_HEAP_ENTRY entry;
printf("Heap ID: %d\n", (DWORD)(ULONG_PTR)heaps[heapIndex]);
entry.lpData = NULL;
while (HeapWalk(heaps[heapIndex], &entry))
{
// Heap32First and Heap32Next ignore entries
// with the PROCESS_HEAP_REGION flag
if (!(entry.wFlags & PROCESS_HEAP_REGION))
{
printf("Block size: %d\n", entry.cbData + entry.cbOverhead);
}
}
}
free(heaps);
return 0;
}
Ходьба по куче с помощью функции HeapWalk является примерно линейной по размеру кучи, в то время как ходьба кучи с функцией Heap32Next имеет примерно квадратный размер кучи. Даже для скромной кучи с 10 000 выделений HeapWalk работает в 10 000 раз быстрее , чем Heap32Next , предоставляя при этом более подробные сведения. Разница в производительности становится еще более существенной по мере увеличения размера кучи.
Более подробный пример обхода кучи с помощью функции HeapWalk см. в разделе Перечисление кучи.