Freigeben über


Durchlaufen der Heapliste

Im folgenden Beispiel wird eine Liste von Heaps für den aktuellen Prozess abgerufen. Mithilfe der CreateToolhelp32Snapshot-Funktion wird eine Momentaufnahme der Heaps verwendet. Anschließend wird die Liste mithilfe der Funktionen Heap32ListFirst und Heap32ListNext durchlaufen. Für jeden Heap werden die Funktionen Heap32First und Heap32Next verwendet, um die Heapblöcke zu durchlaufen.

Hinweis

Heap32First und Heap32Next sind insbesondere für große Heaps ineffizient. Sie sind jedoch nützlich, um andere Prozesse abzufragen, bei denen Sie normalerweise einen Thread in den anderen Prozess einfügen müssten, um die Informationen zu sammeln (diese APIs erledigen dies für Sie).

Im zweiten Beispiel finden Sie eine gleichwertige, viel effizientere Alternative, die HeapWalk anstelle von Heap32First und Heap32Next verwendet. Beachten Sie, dass HeapWalk nur für denselben Prozess verwendet werden kann.

#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;
}

Der folgende Codeausschnitt verwendet die HeapWalk-Funktion , um die Prozessheaps zu durchlaufen, wodurch eine identische Ausgabe wie im vorherigen Beispiel erzeugt wird, aber viel effizienter:

#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;
}

Das Gehen eines Heaps mit der HeapWalk-Funktion ist in etwa linear in der Größe des Heaps, während das Gehen eines Heaps mit der Heap32Next-Funktion in der Größe des Heaps ungefähr quadratisch ist. Selbst für einen bescheidenen Heap mit 10.000 Zuordnungen läuft HeapWalk 10.000 Mal schneller als Heap32Next und liefert detailliertere Informationen. Der Unterschied in der Leistung wird noch dramatischer, wenn die Heapgröße zunimmt.

Ein ausführlicheres Beispiel für das Durchlaufen des Heaps mit der HeapWalk-Funktion finden Sie unter Auflisten eines Heaps.