Compartir a través de


Recorrida de la lista de montones

En el ejemplo siguiente se obtiene una lista de montones para el proceso actual. Toma una instantánea de los montones mediante la función CreateToolhelp32Snapshot y, a continuación, recorre la lista mediante las funciones Heap32ListFirst y Heap32ListNext . Para cada montón, usa las funciones Heap32First y Heap32Next para recorrer los bloques del montón.

Nota:

Heap32First y Heap32Next son ineficaz, especialmente para montones grandes. Sin embargo, son útiles para consultar otros procesos en los que normalmente tendría que insertar un subproceso en el otro proceso para recopilar la información (estas API lo hacen automáticamente).

Vea el segundo ejemplo de una alternativa equivalente, mucho más eficaz, que usa HeapWalk en lugar de Heap32First y Heap32Next. Tenga en cuenta que HeapWalk solo se puede usar para el mismo proceso.

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

El siguiente fragmento de código usa la función HeapWalk para recorrer los montones del proceso, produciendo una salida idéntica al ejemplo anterior, pero mucho más eficazmente:

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

Caminar un montón con la función HeapWalk es aproximadamente lineal en el tamaño del montón, mientras que caminar un montón con la función Heap32Next es aproximadamente cuadrático en el tamaño del montón. Incluso para un montón modesto con 10 000 asignaciones, HeapWalk se ejecuta 10 000 veces más rápido que Heap32Next , al tiempo que proporciona información más detallada. La diferencia en el rendimiento se vuelve aún más dramática a medida que aumenta el tamaño del montón.

Para obtener un ejemplo más detallado de caminar el montón con la función HeapWalk , consulte Enumerar un montón.