Dela via


Gå igenom heap-listan

I följande exempel hämtas en lista över heaps för den aktuella processen. Den tar en ögonblicksbild av heaps med funktionen CreateToolhelp32Snapshot och går sedan igenom listan med hjälp av funktionerna Heap32ListFirst och Heap32ListNext. För varje heap använder den funktionerna Heap32First och Heap32Next för att iterera över heapblocken.

Not

Heap32First och Heap32Next är ineffektiva, särskilt för stora heapar. De är dock användbara för att fråga andra processer där du vanligtvis måste mata in en tråd i den andra processen för att samla in informationen (dessa API:er gör detta åt dig).

Se det andra exemplet för ett motsvarande, mycket effektivare alternativ som använder HeapWalk i stället för Heap32First och Heap32Next. Observera att HeapWalk- endast kan användas för samma process.

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

Följande kodfragment använder funktionen HeapWalk för att gå genom processhögarna och producera identiska utdata till föregående exempel, men mycket mer effektivt:

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

Att gå igenom en hög med HeapWalk-funktionen är ungefär linjär i storleken på högen, medan att gå igenom en hög med Heap32Next-funktionen är ungefär kvadratisk i storleken på högen. Även för en blygsam hög med 10 000 allokeringar körs HeapWalk 10 000 gånger snabbare än Heap32Next samtidigt som den ger mer detaljerad information. Skillnaden i prestanda blir ännu mer dramatisk när heapstorleken ökar.

Ett mer detaljerat exempel på hur du traverserar heapen med funktionen HeapWalk finns i Uppräkning av en heap.