Partager via


Traversée de la liste des tas

L’exemple suivant obtient une liste de tas pour le processus actuel. Il prend une instantané des tas à l’aide de la fonction CreateToolhelp32Snapshot, puis décrit la liste à l’aide des fonctions Heap32ListFirst et Heap32ListNext. Pour chaque tas, il utilise les fonctions Heap32First et Heap32Next pour parcourir les blocs de tas.

Notes

Heap32First et Heap32Next sont inefficaces, en particulier pour les tas volumineux. Toutefois, ils sont utiles pour interroger d’autres processus dans lesquels vous devez généralement injecter un thread dans l’autre processus pour collecter les informations (ces API le font pour vous).

Consultez le deuxième exemple pour une alternative équivalente, beaucoup plus efficace, qui utilise HeapWalk au lieu de Heap32First et Heap32Next. Notez que HeapWalk ne peut être utilisé que pour le même processus.

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

L’extrait de code suivant utilise la fonction HeapWalk pour parcourir les tas de processus, en produisant une sortie identique à l’exemple précédent, mais beaucoup plus efficacement :

#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 marche d’un tas avec la fonction HeapWalk est à peu près linéaire dans la taille du tas, tandis que la marche d’un tas avec la fonction Heap32Next est à peu près quadratique dans la taille du tas. Même pour un tas modeste avec 10 000 allocations, HeapWalk fonctionne 10 000 fois plus vite que Heap32Next tout en fournissant des informations plus détaillées. La différence de performances devient encore plus importante à mesure que la taille du tas augmente.

Pour obtenir un exemple plus détaillé de la marche du tas avec la fonction HeapWalk , consultez Énumération d’un tas.