遍历堆列表
以下示例获取当前进程的堆列表。 它使用 CreateToolhelp32Snapshot 函数快照堆,然后使用 Heap32ListFirst 和 Heap32ListNext 函数遍历列表。 对于每个堆,它使用 Heap32First 和 Heap32Next 函数遍视堆块。
注意
Heap32First 和 Heap32Next 效率低下,尤其是对于大型堆。 但是,它们对于查询其他进程非常有用,这些进程通常需要将线程注入其他进程,以收集信息 (这些 API 为你) 执行此操作。
有关使用 HeapWalk 而不是 Heap32First 和 Heap32Next 的等效、更高效的替代方法,请参阅第二个示例。 请注意, 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 的运行速度也比 Heap32Next 快 10,000 倍,同时提供更详细的信息。 随着堆大小的增加,性能差异变得更加明显。