Condividi tramite


Attraversamento dell'elenco heap

Nell'esempio seguente viene ottenuto un elenco di heaps per il processo corrente. Accetta uno snapshot dell'heaps usando la funzione CreateToolhelp32Snapshot e quindi illustra l'elenco usando le funzioni Heap32ListFirst e Heap32ListNext. Per ogni heap, usa le funzioni Heap32First e Heap32Next per seguire i blocchi heap.

Nota

Heap32First e Heap32Next sono inefficienti, in particolare per gli heaps di grandi dimensioni. Tuttavia, sono utili per eseguire query su altri processi in cui in genere è necessario inserire un thread nell'altro processo per raccogliere le informazioni (queste API eseguono questa operazione).

Vedere il secondo esempio per un equivalente, molto più efficiente, alternativa che usa HeapWalk anziché Heap32First e Heap32Next. Si noti che HeapWalk può essere usato solo per lo stesso processo.

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

Il frammento di codice seguente usa la funzione HeapWalk per seguire l'heaps del processo, generando output identico all'esempio precedente, ma molto più efficiente:

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

La passeggiata di un heap con la funzione HeapWalk è approssimativamente lineare nella dimensione dell'heap, mentre la passeggiata di un heap con la funzione Heap32Next è approssimativamente quadratica nella dimensione dell'heap. Anche per un heap modesto con 10.000 allocazioni, HeapWalk esegue 10.000 volte più veloce di Heap32Next fornendo informazioni più dettagliate. La differenza nelle prestazioni diventa ancora più drammatica quando le dimensioni dell'heap aumentano.

Per un esempio più dettagliato dell'heap con la funzione HeapWalk , vedere Enumerazione di un heap.