Percorrendo a lista de heaps

O exemplo a seguir obtém uma lista de heaps para o processo atual. Ele usa uma instantâneo dos heaps usando a função CreateToolhelp32Snapshot e, em seguida, percorre a lista usando as funções Heap32ListFirst e Heap32ListNext. Para cada heap, ele usa as funções Heap32First e Heap32Next para percorrer os blocos de heap.

Observação

Heap32First e Heap32Next são ineficientes, especialmente para heaps grandes. No entanto, eles são úteis para consultar outros processos em que você normalmente teria que injetar um thread no outro processo para coletar as informações (essas APIs fazem isso para você).

Consulte o segundo exemplo para obter uma alternativa equivalente, muito mais eficiente, que usa HeapWalk em vez de Heap32First e Heap32Next. Observe que o HeapWalk só pode ser usado para o mesmo 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;
}

O snippet de código a seguir usa a função HeapWalk para percorrer os heaps de processo, produzindo uma saída idêntica ao exemplo anterior, mas com muito mais eficiência:

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

Andar em um heap com a função HeapWalk é aproximadamente linear no tamanho do heap, enquanto andar um heap com a função Heap32Next é aproximadamente quadrático no tamanho do heap. Mesmo para um heap modesto com 10.000 alocações, HeapWalk é executado 10.000 vezes mais rápido que Heap32Next , fornecendo informações mais detalhadas. A diferença de desempenho torna-se ainda mais dramática à medida que o tamanho do heap aumenta.

Para obter um exemplo mais detalhado de como percorrer o heap com a função HeapWalk , consulte Enumerando um Heap.