Compartir a través de


Ejercicio 2: Seguimiento de asignaciones de procesos en modo de usuario

Las asignaciones del montón se realizan directamente a través de las API de montón (HeapAlloc, HeapRealloc y asignaciones de C/C++, como nuevas, asignación, reasignación, calloc) y se aprotelan mediante tres tipos de montones:

  1. Montón NT de mainline : solicitudes de asignación de servicios de tamaños inferiores a 64 KB.

  2. Montón de fragmentación baja : compuesto por subsitios que asignación de servicios solicitan bloques de tamaño fijo.

  3. VirtualAlloc : solicitudes de asignación de servicios de tamaños superiores a 64 KB.

VirtualAlloc se usa para asignaciones de memoria dinámica de gran tamaño que se realizan directamente a través de la API VirtualAlloc . El uso típico suele ser para mapas de bits o búferes. Puede usar VirtualAlloc para reservar un bloque de páginas y, a continuación, realizar llamadas adicionales a VirtualAlloc para confirmar páginas individuales desde el bloque reservado. Esto permite que un proceso reserve un intervalo de su espacio de direcciones virtuales sin consumir almacenamiento físico hasta que sea necesario.

Hay dos conceptos que comprender en esta área:

  1. Memoria reservada: reserva un intervalo de direcciones para el uso, pero no adquiere recursos de memoria.

  2. Memoria confirmada: garantiza que la memoria física o el espacio del archivo de página estarán disponibles si se hace referencia a las direcciones.

En este ejercicio, aprenderá a recopilar seguimientos para investigar cómo un proceso de modo de usuario asigna memoria.

El ejercicio se centra en un proceso de prueba ficticio denominado MemoryTestApp.exe que asigna memoria a través de:

  1. La API VirtualAlloc para confirmar búferes de memoria grandes.

  2. Operador nuevo de C++ para crear instancias de objetos pequeños.

Puede descargar MemoryTestApp.exedesde aquí.

Paso 1: Recopilar un seguimiento virtualAlloc/montón mediante WPR

Las asignaciones de memoria de gran tamaño suelen ser las que afectan a la superficie de un proceso y son administradas por la API VirtualAlloc . Aquí es donde deben comenzar todas las investigaciones, pero también es posible que un proceso se comporte mal con asignaciones más pequeñas (por ejemplo, pérdidas de memoria mediante el nuevo operador en C++, etc.). El seguimiento del montón resulta útil cuando se produce esta situación.

Paso 1.1: Preparación del sistema para el seguimiento del montón

El seguimiento del montón debe considerarse opcional y realizarse cuando el análisis de VirtualAlloc no proporciona ninguna explicación pertinente para un problema de uso de memoria. El seguimiento del montón tiende a generar seguimientos más grandes y se recomienda habilitar el seguimiento solo para los procesos individuales que está investigando.

Agregue la clave del Registro para el proceso de interés (MemoryTestApp.exe en este caso); A continuación, se habilita el seguimiento del montón para cada creación posterior del proceso.

reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /t REG_DWORD /d 1 /f

Paso 1.2: Capturar un seguimiento mediante WPR

En este paso, recopilará un seguimiento mediante WPR que contiene datos de VirtualAlloc y Montón .

  1. Abra WPR y modifique la configuración de seguimiento.

    1. Seleccione los proveedores VirtualAlloc y Montón .

    2. Seleccione general como escenario de rendimiento.

    3. Seleccione general como modo de registro.

      Captura de pantalla del menú de opciones de seguimiento de WPR.

  2. Haga clic en Iniciar para iniciar el seguimiento.

  3. Inicie MemoryTestApp.exey espere a que finalice el proceso (debería tardar unos 30 segundos).

  4. Vuelva a WPR, guarde el seguimiento y ábralo con Windows Analizador de rendimiento (WPA).

  5. Abra el menú Seguimiento y seleccione Configurar ruta de acceso de símbolos.

    • Especifique la ruta de acceso de la caché de símbolos. Para obtener más información sobre los símbolos, vea la página Compatibilidad con símbolos en MSDN.
  6. Abra el menú Seguimiento y seleccione Cargar símbolos.

Ahora tiene un seguimiento que contiene todos los patrones de asignación de memoria para el proceso deMemoryTestApp.exe durante su vigencia.

Paso 2: Revisar las asignaciones dinámicas de VirtualAlloc

Los datos detallados de VirtualAlloc se exponen a través del gráfico "Duración de confirmación de VirtualAlloc" en WPA. Las columnas clave de interés son las siguientes:

Columna Descripción
Process

Nombre del proceso que realiza asignaciones de memoria a través de VirtualAlloc.

Pila de confirmación

Pila de llamadas que muestra la ruta de acceso del código que conduce a la asignación de memoria.

Hora de confirmación

Marca de tiempo de la asignación de memoria.

Hora de descommitción

Marca de tiempo de cuando se liberó la memoria.

Impacto del tamaño

El tamaño de las asignaciones pendientes o la diferencia de tamaño entre el inicio y el final del intervalo de tiempo seleccionado. Este tamaño se ajusta en función del puerto de vista seleccionado.

El valor tamaño de impacto será cero si toda la memoria asignada por un proceso se libera al final del intervalo visualizados en WPA.

Tamaño

Suma acumulativa de todas las asignaciones durante el intervalo de tiempo seleccionado.

Siga estos pasos para analizar MemoryTestApp.exe

  1. Busque el gráfico Duración de confirmación de VirtualAlloc en la categoría Memoria del Explorador de Graph.

  2. Arrastre y coloque las duraciones de confirmación de VirtualAlloc en la pestaña Análisis .

  3. Organice la tabla para mostrar estas columnas. Haga clic con el botón derecho en los encabezados de columna para agregar o quitar columnas.

    1. Process

    2. Tipo de impacto

    3. Pila de confirmación

    4. Hora de confirmación y Hora de descommitción

    5. Recuento

    6. Impacto del tamaño y el tamaño

  4. Busque MemoryTestApp.exe en la lista de procesos.

  5. Aplique un filtro para mantener solo MemoryTestApp.exe en el gráfico.

    • Haga clic con el botón derecho y seleccione Filtrar a selección.

Captura de pantalla que muestra cómo filtrar los resultados.

La ventanilla de análisis debe tener un aspecto similar al siguiente:

Gráfico de ejemplo del aspecto de los datos cuando se filtran.

En el ejemplo anterior, dos valores son de interés:

  • Tamaño de 126 MB: indica que MemoryTestApp.exe asignó un total de 125 MB durante su vida útil. Representa la suma acumulativa de todas las llamadas API de VirtualAlloc realizadas por el proceso y sus dependencias.

  • Impacto del tamaño de 0 MB: indica que toda la memoria asignada por el proceso se libera al final del intervalo de tiempo que se está analizando actualmente. El sistema no sufrió un aumento de su uso de memoria de estado estable.

Paso 2.1: Análisis del uso de memoria de estado estable

Al investigar la asignación de memoria, debe intentar responder a la pregunta: "¿Por qué aumenta el uso de memoria de estado estable para este escenario?" En el ejemplo deMemoryTestApp.exe , puede ver que tiene aproximadamente 10 MB de memoria de estado estable asignada al principio y, a continuación, aumenta a 20 MB a medio camino.

Captura de pantalla de datos de ejemplo que muestran el uso de memoria.

Para investigar este comportamiento, limite el zoom a alrededor del intervalo de tiempo cuando se produce el aumento repentino en medio del seguimiento.

Captura de pantalla que muestra cómo acercar los datos.

La ventanilla debe tener este aspecto.

Captura de pantalla de los datos de ejemplo después de aplicar el grafo de la opción de zoom con VirtualAlloc Commit LifeTimes y Confirmación pendiente por proceso

Como puede ver, el tamaño de impacto ahora es de 10 MB. Esto significa que, entre el inicio y el final del intervalo de tiempo que se analiza, hay un aumento de 10 MB en el uso de memoria de estado estable.

  1. Ordene por Impacting Size haciendo clic en el encabezado de columna.

  2. Expanda la fila MemoryTestApp.exe (en la columna Proceso ).

  3. Expanda la fila Impacto (en la columna Tipo de impacto ).

  4. Navegue por el proceso Commit Stack hasta que encuentre la función que asignó 10 MB de memoria.

    Captura de pantalla de la tabla de datos de ejemplo que muestra el número de línea, el proceso, el tipo de impacto, la pila de confirmación, la hora de confirmación, la hora de descommitir, el recuento y el tamaño de impacto

En este ejemplo, la función Main de MemoryTestApp.exe asigna 10 MB de memoria en medio de la carga de trabajo llamando directamente a VirtualAlloc. En el mundo real, el desarrollador de aplicaciones debe determinar si la asignación es razonable o si el código se podría reorganizar para minimizar el aumento del uso de memoria de estado estable.

Ahora puedes deshacer la ventanilla en WPA.

Pantallahsot del menú unzoom.

Paso 2.2: Análisis del uso de memoria transitorio (o pico)

Al investigar las asignaciones de memoria, debe intentar responder a la pregunta: "¿Por qué hay un pico transitorio en el uso de memoria para esta parte del escenario?" Las asignaciones transitorias provocan picos en el uso de memoria y pueden provocar fragmentación e insertar contenido valioso fuera de la memoria caché en espera del sistema cuando hay presión de memoria.

En el ejemplo MemoryTest , puede ver que hay 10 picos diferentes de uso de memoria (de 10 MB) dispersos uniformemente en el seguimiento.

Captura de pantalla del gráfico que muestra los datos de uso de memoria.

Limite el zoom a los cuatro últimos picos para centrarse en una región más pequeña de interés y reducir el ruido de comportamientos no relevantes.

Captura de pantalla de la opción de zoom.

La ventanilla debe tener este aspecto:

Captura de pantalla del gráfico que muestra los datos de uso de memoria mediante la opción zoom.

  1. Ordene por Tamaño haciendo clic en el encabezado de columna.

  2. Expanda la fila MemoryTestApp.exe (en la columna Proceso ).

  3. Haga clic en la fila Transitorio (en la columna Tipo de impacto ).

    • Esto debe resaltarse en azul todos los picos de uso de memoria en la ventanilla.
  4. Tenga en cuenta el valor de las distintas columnas:

    1. Count = 4: indica que se realizaron cuatro asignaciones de memoria transitorias durante ese intervalo de tiempo.

    2. Impacto del tamaño = 0 MB: esto indica que las cuatro asignaciones de memoria transitorias se liberaron al final del intervalo de tiempo.

    3. Tamaño = 40 MB: indica que la suma de las cuatro asignaciones de memoria transitorias equivale a 40 MB de memoria.

  5. Navegue por el proceso Commit Stack hasta que encuentre las funciones que asignaron 40 MB de memoria.

    Captura de pantalla de los datos de uso de memoria.

En este ejemplo, la función Main de MemoryTestApp.exe llama a una función denominada Operation1, que a su vez llama a una función denominada ManipulateTemporaryBuffer. Esta función ManipulateTemporaryBuffer llama directamente a VirtualAlloc cuatro veces, creando y liberando un búfer de memoria de 10 MB cada vez. Los búferes solo duran 100 ms cada uno. La asignación y los tiempos libres de los búferes se representan mediante las columnas Tiempo de confirmación y Hora de descommitido .

En el mundo real, el desarrollador de aplicaciones determinaría si esas asignaciones de búfer temporal transitorias de corta duración son necesarias o si se pueden reemplazar mediante un búfer de memoria permanente para la operación.

Ahora puedes deshacer la ventanilla en WPA.

Paso 3: Revisar las asignaciones dinámicas del montón

Hasta ahora, el análisis solo se ha centrado en asignaciones de memoria de gran tamaño que la API VirtualAlloc ofrece. El siguiente paso consiste en determinar si hay problemas con otras asignaciones pequeñas realizadas por el proceso, mediante los datos del montón recopilados inicialmente.

Los datos detallados del montón se exponen a través del gráfico "Asignaciones del montón" en WPA. Las columnas clave de interés son las siguientes:

Columna Descripción
Process Nombre del proceso que realiza la asignación de memoria.
Handle

Identificador del montón que se usa para atender la asignación.

Se pueden crear montones, por lo que podría haber varios identificadores de montón para el proceso.

Pila Pila de llamadas que muestra la ruta de acceso de código que conduce a la asignación de memoria.
Tiempo de asignación Marca de tiempo de la asignación de memoria.
Impacto del tamaño El tamaño de las asignaciones pendientes o la diferencia entre el inicio y el final de la ventanilla seleccionada. Este tamaño se ajusta en función del intervalo de tiempo seleccionado.
Tamaño Suma acumulativa de todas las asignaciones o desasignaciones.

Siga estos pasos para analizar MemoryTestApp.exe

  1. Busque el gráfico Asignaciones del montón en la categoría Memoria del Explorador de Graph.

  2. Arrastre y coloque las asignaciones del montón en la pestaña Análisis .

  3. Organice la tabla para mostrar estas columnas:

    1. Process

    2. Handle

    3. Tipo de impacto

    4. Pila

    5. AllocTime

    6. Recuento

    7. Impacto del tamaño y el tamaño

  4. Busque MemoryTestApp.exe en la lista de procesos.

  5. Aplique un filtro para mantener solo MemoryTestApp.exe en el gráfico.

    • Haga clic con el botón derecho y seleccione Filtrar a selección.

La ventanilla debe tener este aspecto:

Captura de pantalla de los datos de ejemplo que muestran el gráfico asignaciones del montón de tamaño pendiente por proceso y identificador

En este ejemplo, puede ver que uno de los montones aumenta constantemente en tamaño a lo largo del tiempo a una velocidad constante. Hay 1200 asignaciones de memoria en ese montón, teniendo en cuenta 130 KB de memoria usada al final del intervalo.

  1. Acercar un intervalo más pequeño (por ejemplo, 10 segundos) en medio del seguimiento.

  2. Expanda el identificador principal que muestra la mayor cantidad de asignaciones (como se muestra en la columna Tamaño de impacto ).

  3. Expanda el tipo de impacto .

  4. Navegue por el proceso Stack hasta que encuentre la función responsable de asignar toda esta memoria.

    Captura de pantalla de la tabla de datos de ejemplo que muestra Process, Handle, Impacting Type, Stack, AllocTime, Count, Impacting Size y Size con dos filas seleccionadas

En este ejemplo, la función Main de MemoryTestApp.exe llama a una función denominada InnerLoopOperation. Esta función InnerLoopOperation asigna 40 bytes de memoria 319 veces a través del operador nuevo de C++. Esta memoria permanece asignada hasta que finaliza el proceso.

En el mundo real, el desarrollador de aplicaciones debe determinar si este comportamiento implica una posible pérdida de memoria y corregir el problema.

Paso 4: Limpiar el sistema de prueba

Una vez completado el análisis, debe limpiar el registro para asegurarse de que el seguimiento del montón está deshabilitado para el proceso. Ejecute este comando en un símbolo del sistema con privilegios elevados:

reg delete "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /f