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:
Montón NT de mainline : solicitudes de asignación de servicios de tamaños inferiores a 64 KB.
Montón de fragmentación baja : compuesto por subsitios que asignación de servicios solicitan bloques de tamaño fijo.
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:
Memoria reservada: reserva un intervalo de direcciones para el uso, pero no adquiere recursos de memoria.
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:
La API VirtualAlloc para confirmar búferes de memoria grandes.
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 .
Abra WPR y modifique la configuración de seguimiento.
Seleccione los proveedores VirtualAlloc y Montón .
Seleccione general como escenario de rendimiento.
Seleccione general como modo de registro.
Haga clic en Iniciar para iniciar el seguimiento.
Inicie MemoryTestApp.exey espere a que finalice el proceso (debería tardar unos 30 segundos).
Vuelva a WPR, guarde el seguimiento y ábralo con Windows Analizador de rendimiento (WPA).
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.
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
Busque el gráfico Duración de confirmación de VirtualAlloc en la categoría Memoria del Explorador de Graph.
Arrastre y coloque las duraciones de confirmación de VirtualAlloc en la pestaña Análisis .
Organice la tabla para mostrar estas columnas. Haga clic con el botón derecho en los encabezados de columna para agregar o quitar columnas.
Process
Tipo de impacto
Pila de confirmación
Hora de confirmación y Hora de descommitción
Recuento
Impacto del tamaño y el tamaño
Busque MemoryTestApp.exe en la lista de procesos.
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 de análisis debe tener un aspecto similar al siguiente:
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.
Para investigar este comportamiento, limite el zoom a alrededor del intervalo de tiempo cuando se produce el aumento repentino en medio del seguimiento.
La ventanilla debe tener este aspecto.
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.
Ordene por Impacting Size haciendo clic en el encabezado de columna.
Expanda la fila MemoryTestApp.exe (en la columna Proceso ).
Expanda la fila Impacto (en la columna Tipo de impacto ).
Navegue por el proceso Commit Stack hasta que encuentre la función que asignó 10 MB de memoria.
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.
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.
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.
La ventanilla debe tener este aspecto:
Ordene por Tamaño haciendo clic en el encabezado de columna.
Expanda la fila MemoryTestApp.exe (en la columna Proceso ).
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.
Tenga en cuenta el valor de las distintas columnas:
Count = 4: indica que se realizaron cuatro asignaciones de memoria transitorias durante ese intervalo de tiempo.
Impacto del tamaño = 0 MB: esto indica que las cuatro asignaciones de memoria transitorias se liberaron al final del intervalo de tiempo.
Tamaño = 40 MB: indica que la suma de las cuatro asignaciones de memoria transitorias equivale a 40 MB de memoria.
Navegue por el proceso Commit Stack hasta que encuentre las funciones que asignaron 40 MB 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
Busque el gráfico Asignaciones del montón en la categoría Memoria del Explorador de Graph.
Arrastre y coloque las asignaciones del montón en la pestaña Análisis .
Organice la tabla para mostrar estas columnas:
Process
Handle
Tipo de impacto
Pila
AllocTime
Recuento
Impacto del tamaño y el tamaño
Busque MemoryTestApp.exe en la lista de procesos.
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:
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.
Acercar un intervalo más pequeño (por ejemplo, 10 segundos) en medio del seguimiento.
Expanda el identificador principal que muestra la mayor cantidad de asignaciones (como se muestra en la columna Tamaño de impacto ).
Expanda el tipo de impacto .
Navegue por el proceso Stack hasta que encuentre la función responsable de asignar toda esta memoria.
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