Process Explorer / Handle / VMMap en la práctica ── cómo rastrear cuelgues, fugas y «archivo en uso» desde el estado actual

· Actualizado el: · · Sysinternals, Process Explorer, VMMap, Fuga de handles, Fuga de memoria, Investigación de fallos, Windows, Funcionamiento de larga duración

«Si lo reiniciamos el lunes por la mañana, se soluciona» ── es una frase que he escuchado muchas veces en consultas de mantenimiento de aplicaciones vinculadas a equipos industriales. Justo después de arrancar, todo funciona con fluidez, pero hacia el jueves los cambios de pantalla empiezan a ir con retraso, y el viernes por la tarde, al pulsar un botón, la respuesta tarda varios segundos en llegar. De vez en cuando aparece un error nunca visto, algo como «el handle no es válido». Y al reiniciar, todo vuelve a la normalidad como si nada hubiera pasado. Cuando esto ocurre, la operación termina fijándose en un «reinicio semanal», y pasan varios años sin que nadie conozca la causa raíz.

Por más que se examinen los registros, este tipo de síntomas no permite llegar a la causa. Lo que hace falta es observar directamente «qué y cuánto está reteniendo ese proceso en este preciso instante». En la entrega anterior, la «Guía práctica de Process Monitor (ProcMon)», tratamos ProcMon, que registra la secuencia temporal de operaciones. En esta ocasión, como continuación y segunda entrega práctica de Sysinternals, organizamos las herramientas que observan el estado ── Process Explorer, Handle y VMMap ── según los tres grandes síntomas de las aplicaciones de funcionamiento continuo: «cada vez va más lento», «no puedo eliminar el archivo» y «se quedó colgado».

El entorno que se presupone en este artículo es el siguiente.

  • SO ── según los requisitos oficiales de Process Explorer, el sistema operativo debe ser Windows 11 o posterior en clientes y Windows Server 2016 o posterior en servidores.1
  • Arquitectura ── en entornos de 64 bits, al ejecutar procexp.exe se extrae y ejecuta automáticamente la versión de 64 bits. Para ver correctamente la pila y los handles de procesos de 64 bits, es necesario ejecutar esta versión de 64 bits.
  • Permisos ── para fines de investigación, ejecutar «como administrador» es, en la práctica, imprescindible. Con permisos normales, tanto la pila de subprocesos como la lista de handles muestran «Acceso denegado», al menos para los procesos de otros usuarios o de servicios. La versión de línea de comandos handle.exe requiere oficialmente permisos de administrador.2
  • Primera ejecución ── aparece un cuadro de diálogo de aceptación del EULA (Contrato de licencia de usuario final). En scripts o ejecuciones desatendidas, la aceptación se indica explícitamente con el modificador /accepteula (capítulo 8).

Cabe señalar que, aunque este artículo trata sobre el manejo de herramientas con interfaz gráfica, no incluye capturas de pantalla. En su lugar, se escriben los nombres de menú y las combinaciones de teclas tal como aparecen en la aplicación, de modo que se pueda leer mientras se tiene la herramienta abierta.

1. Primero, la conclusión

  • ProcMon muestra el «historial»; Process Explorer, el «presente». Process Explorer es una herramienta que permite listar y buscar los handles abiertos y las DLL cargadas por cada proceso, y la propia documentación oficial afirma que es adecuada para investigar problemas de versión de DLL y fugas de handles.1
  • Para «no puedo eliminar o reemplazar el archivo», Find Handle or DLL (Ctrl+F) es el camino más rápido. Basta con buscar por una parte de la ruta para identificar en segundos el proceso que retiene ese archivo (capítulo 3).
  • Para «se quedó colgado», se observa la pila de subprocesos en Propiedades del proceso → pestaña Threads. Sin embargo, si no se configuran los símbolos (dbghelp.dll y la ruta de símbolos), solo se obtiene una lista de direcciones (capítulo 4).13
  • Para «cada vez va más lento», se añaden columnas y se observa la tendencia. Se agregan las cuatro columnas Handle Count, USER Objects, GDI Objects y Private Bytes, y se busca cuál sigue aumentando con el paso del tiempo. Los objetos GDI/USER tienen un límite por proceso, y al alcanzarlo empiezan a fallar la creación de ventanas y el dibujado (capítulo 5).4
  • La versión de línea de comandos, handle.exe, es adecuada para la observación periódica mediante scripts. Con handle -s -p <proceso> se puede registrar periódicamente el número de handles por tipo. El cierre forzado de handles con -c está advertido oficialmente como causa de inestabilidad, así que en principio no se utiliza.2
  • El desglose de «Private Bytes sigue aumentando» se obtiene con VMMap. Si es Heap, se sospecha de código nativo; si es Managed Heap, de .NET: primero se decide en qué terreno buscar al culpable y luego se pasa a la herramienta especializada (capítulo 6).5
  • Cuando lo sospechoso no es un proceso concreto sino la memoria de todo el sistema operativo, se usa RAMMap.6 Si se trata de un bloqueo (crash), se pasa a recopilar volcados con ProcDump (véase «Introducción a la recopilación de volcados de fallos de Windows»).
  • Ninguna de estas herramientas requiere instalación, y todas se pueden ejecutar directamente desde Sysinternals Live. Son fáciles de llevar incluso a un PC de equipo sin conexión, aunque los símbolos son la única parte que requiere preparación previa (capítulo 8).7

2. Fundamentos de Process Explorer ── ejecución como administrador, sustitución del Administrador de tareas y cómo leer la pantalla

Process Explorer no requiere instalación: basta con descomprimir el ZIP y ejecutar procexp.exe (en 64 bits, se ejecuta automáticamente procexp64).1 Como es una herramienta que permite ver el interior de procesos y servicios de otros usuarios, durante una investigación siempre debe ejecutarse «como administrador». Si se inicia con permisos normales, precisamente los procesos que interesan mostrarán «Acceso denegado», y no se podrán ver ni la pila ni los handles.

En las máquinas dedicadas a la investigación, si se activa Options → Replace Task Manager, cualquier llamada al Administrador de tareas desde Ctrl+Shift+Esc o la barra de tareas se sustituye directamente por Process Explorer. El efecto de «que se abra la herramienta habitual en el momento crítico» es discretamente importante, y en nuestra empresa todas las máquinas de desarrollo tienen esta sustitución activada (para revertirlo se usa el mismo menú).

La pantalla se compone de dos paneles: el árbol de procesos arriba y los detalles del proceso seleccionado abajo. En el panel inferior, con View → Lower Pane View se alterna entre la vista Handles (lista de handles abiertos) y la vista DLLs (lista de DLL cargadas y archivos mapeados en memoria).1 Lo primero que hay que aprender es el significado del color de cada fila (se puede consultar y modificar en Options → Configure Colors).

Color (predeterminado) Significado
Verde Proceso recién iniciado (aproximadamente 1 segundo de forma predeterminada)
Rojo Proceso que está terminando
Azul claro Proceso de la misma cuenta de usuario que la propia
Rosa Proceso que aloja un servicio
Morado Sospecha de ejecutable «empaquetado» (comprimido/ofuscado)
Gris oscuro Proceso suspendido

Anomalías como «un proceso nace en verde por un instante, enseguida se pone rojo y desaparece», repitiéndose sin fin, se detectan solo con la vista de árbol y la codificación por colores. Como la relación padre-hijo de los procesos se ve en el árbol, también se aprecia de un vistazo «de quién es hijo este conhost.exe» o «si la aplicación la inicia un servicio o el Programador de tareas».

3. «El archivo está en uso y no se puede eliminar» ── cómo identificar al culpable con Find Handle or DLL

«No puedo eliminar el archivo de registro», «al intentar actualizar, el exe está en uso», «no puedo extraer la memoria USB de forma segura» ── la investigación de este tipo de síntomas termina con Find → Find Handle or DLL (Ctrl+F).1 Los pasos son los siguientes cinco:

  1. Ejecutar Process Explorer como administrador (si se olvida este paso, no se verá el proceso responsable cuando se trate de un servicio o de un proceso de otro usuario)
  2. Abrir el menú Find > Find Handle or DLL… (atajo Ctrl+F)
  3. En el campo de búsqueda, escribir una parte del nombre de archivo o de carpeta (por ejemplo, report.csv, D:\Data). No hace falta la ruta completa: la búsqueda es por coincidencia parcial
  4. Pulsar Search. Aparece la lista de procesos que tienen abierto un handle con ese nombre, o que han cargado esa DLL
  5. Al hacer clic en una fila del resultado, el proceso correspondiente queda seleccionado en el panel superior y el handle correspondiente se resalta en el panel inferior

Una vez identificado el proceso, la solución correcta es «terminarlo de forma adecuada». También es posible cerrar el handle a la fuerza haciendo clic derecho sobre él en Process Explorer y seleccionando Close Handle, pero por el mismo motivo que se explica más adelante para handle -c, no se recomienda en producción.

Conviene tener presentes de antemano los límites de esta búsqueda. Solo encuentra objetos que tienen nombre. Los eventos, mutexes o handles de subproceso sin nombre no se pueden buscar por nombre, por muchos que se hayan abierto. Para investigaciones como «no puedo eliminar el archivo», donde existe un nombre en forma de ruta, es el método más potente, pero en la investigación de fugas de handles del capítulo 5 este método no sirve: hay que cambiar a la agrupación por tipo (handle -s) y a ordenar la vista Handles del panel inferior por Type (el caso práctico del capítulo 7 es un ejemplo real de esto).

La vista DLLs también sirve para confirmar «qué versión de qué DLL, ubicada dónde, se cargó realmente». Esta pantalla es la contraparte del apartado 5.2 del artículo anterior sobre ProcMon, «Solo falla al iniciar en este entorno ── cómo rastrear la búsqueda de DLL», a la hora de verificar problemas de versión de DLL como «se estaba cargando una DLL antigua» o «no se está leyendo la versión corregida que se supone que se desplegó». Aquel apartado sigue en orden cronológico «una sucesión de NAME NOT FOUND en el orden de búsqueda, y dónde se produce el SUCCESS (o si nunca se encuentra)», y muestra dónde se buscó. En cambio, esta vista DLLs muestra qué se acabó cargando y desde dónde. Para más detalles, consulte la «Guía práctica de Process Monitor (ProcMon)».

En primer lugar, «cómo reemplazar de forma segura un exe/DLL en uso» no es un problema de investigación, sino de diseño. El artículo hermano publicado el mismo día, «Cómo reemplazar un exe/DLL en uso», trata el diseño de reemplazo, incluido Restart Manager, así que quienes construyan un mecanismo de actualización pueden consultarlo allí.

4. «Se quedó colgado» ── cómo leer la pila de subprocesos en la pestaña Threads

La ventana se pone en blanco y deja de responder. Antes de forzar el cierre, observe la pila de subprocesos en la pestaña Threads. Los pasos son los siguientes cuatro:

  1. Hacer doble clic en el proceso objetivo en el panel superior (o clic derecho → Properties…). Se abre la ventana de propiedades
  2. Cambiar a la pestaña Threads. Se muestran el uso de CPU, el número de ciclos y la dirección de inicio de cada subproceso
  3. Elegir el subproceso a examinar. El primer candidato es el que sigue consumiendo CPU, o aquel cuya dirección de inicio corresponde al EXE principal de la aplicación (en muchos casos, es el subproceso de la interfaz de usuario)
  4. Pulsar el botón Stack. Se muestra, empezando por la llamada más reciente, en qué función está detenido actualmente ese subproceso

La mayoría de los cuelgues se deben a que «el subproceso de interfaz de usuario está esperando algo», así que si en la parte superior de la pila aparecen WaitForSingleObject, EnterCriticalSection o una espera síncrona de E/S de red o serie, esa es la causa directa.

Sin embargo, si no se configuran los símbolos, la pila queda reducida a una sucesión de direcciones y nombre_de_módulo+0x1234, prácticamente ilegible. En Options → Configure Symbols se configuran los dos elementos siguientes:

Dbghelp.dll path:
  C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll
  ※ Especifique el archivo incluido en WinDbg (Debugging Tools for Windows)

Symbols path:
  srv*C:\Symbols*https://msdl.microsoft.com/download/symbols
  ※ C:\Symbols es la caché local. A partir de la segunda vez, se lee desde aquí

Hay dos puntos clave. Primero, el dbghelp.dll predeterminado que se encuentra en System32 no admite la descarga desde un servidor de símbolos, por lo que hay que apuntar al que viene con WinDbg. Segundo, tal como indica la documentación oficial, si se usa un servidor de símbolos, symsrv.dll debe estar en la misma carpeta que el dbghelp.dll especificado (en la carpeta de instalación de WinDbg, ambos ya están presentes).1 El formato de ruta de símbolos srv*caché*URL_del_servidor y el servidor público de símbolos de Microsoft https://msdl.microsoft.com/download/symbols son el mismo mecanismo que usa WinDbg.3 Para leer la pila de la aplicación propia también hace falta el PDB de la compilación propia, así que conviene añadir a la ruta de símbolos, separada por punto y coma, la carpeta donde se guardan esos PDB.

De dónde obtener ese dbghelp.dll es lo primero con lo que uno se atasca aquí. La ruta C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\ que aparece arriba es una carpeta que se crea al instalar Debugging Tools for Windows. Hay tres formas de obtenerlo.8

Vía de obtención Situación recomendada
En el instalador del Windows SDK, seleccionar solo «Debugging Tools for Windows» Es la vía más rápida para este uso. Si se desmarcan todas las demás casillas y se ejecuta, se instala solo el depurador, sin el SDK en sí8
Instalarlo como parte del Windows SDK / WDK Cuando la máquina de desarrollo también necesita el SDK para otros usos
Instalar WinDbg de forma independiente (winget install Microsoft.WinDbg o Microsoft Store) Cuando se quiere usar WinDbg en sí. Sin embargo, al instalarse en formato de paquete, no queda en una ruta fija como la de arriba9

Lo que se configura en Process Explorer es la ruta del archivo dbghelp.dll, así que, tras la instalación, confirme que dbghelp.dll y symsrv.dll están juntos en esa carpeta antes de especificarla.

En el caso de aplicaciones .NET, la pila de la pestaña Threads se centra en los frames nativos, y es posible que los nombres de método administrados no aparezcan con precisión. Si se quiere rastrear en serio un cuelgue o interbloqueo administrado, lo más seguro es capturar un volcado durante el cuelgue y examinarlo con WinDbg + SOS (véase «Leer volcados de fallos con WinDbg + SOS»). La división de roles es: la pestaña Threads sirve para «hacerse una idea en el sitio en tres minutos», y el volcado, para «llevárselo y confirmarlo». Por cierto, no pulse los botones Kill/Suspend de la pestaña Threads sobre procesos en producción: lo que pretendía ser observación se convierte en intervención.

5. «Cada vez va más lento» ── monitorización de fugas con las columnas de número de handles, USER/GDI y handle.exe

La causa clásica de degradación en aplicaciones de funcionamiento continuo son las fugas de handles, de objetos GDI/USER y de memoria. Process Explorer también es excelente como herramienta de monitorización: desde View → Select Columns se añaden las siguientes columnas.

  • Pestaña Process PerformanceHandle Count (número de handles de objetos del kernel)
  • Pestaña Process MemoryPrivate Bytes, Virtual Size, USER Objects, GDI Objects

Lo que hay que observar no es el valor absoluto, sino la tendencia. En una aplicación sana, el número de handles sube y baja según las operaciones, pero se mantiene dentro de un rango; si hay una fuga, se vuelve una línea ascendente que «aumenta con cada operación y nunca vuelve a bajar». Basta con guardar capturas de pantalla cada hora, o por la mañana y por la tarde, para que al día siguiente ya se aprecie la tendencia. Los objetos GDI y USER tienen un límite por proceso (10.000 de forma predeterminada, modificable mediante GDIProcessHandleQuota en el registro, entre otros) y un límite teórico de toda la sesión de 65.536; al alcanzar el límite, empiezan a fallar la creación de plumas, pinceles y ventanas.4 «El dibujado de la pantalla se corrompe los viernes» suele deberse precisamente a esto.

Para entornos donde no se puede abrir la GUI, o para la observación periódica mediante scripts, se usa la versión de línea de comandos handle.exe. Es una herramienta de línea de comandos para listar y buscar handles, y requiere permisos de administrador.2

:: Quién tiene abierto este archivo/carpeta (búsqueda por coincidencia parcial del nombre)
handle.exe /accepteula report.csv
handle.exe D:\Data

:: Volcar todos los tipos de handle, no solo archivos, filtrando por nombre de proceso
handle.exe -a -p MyEquipApp

:: Agregar el número de handles por tipo -- esto es lo que se registra para la observación periódica de fugas
handle.exe -s -p MyEquipApp.exe >> C:\Logs\handles_%date:~0,4%%date:~5,2%%date:~8,2%.log

Una aclaración sobre %date:~0,4% de la tercera línea. Esto es una expansión de subcadena de variable de entorno, y tanto dentro de un archivo por lotes como al escribirlo directamente en el símbolo del sistema, se usa de la misma forma, con un solo % (la duplicación a %% solo es necesaria para las variables de for y cuando se quiere escribir un % literal; esta notación no entra en esos casos).

Sin embargo, el contenido de %date% depende del formato corto de fecha del sistema operativo, por lo que desplazamientos como ~0,4 (los primeros 4 caracteres = el año) varían según el entorno. El valor predeterminado en la versión japonesa de Windows es yyyy/MM/dd, con lo que el ejemplo anterior funciona, pero si la configuración regional del PC del equipo es distinta, el nombre de archivo se genera de forma incorrecta. Si el script de observación periódica se va a distribuir entre varios entornos, la generación de la fecha, al menos, debe basarse en un método cuyo formato esté garantizado.

:: Forma de escritura independiente del formato de fecha del entorno (para usar dentro de un archivo por lotes)
for /f %%d in ('powershell -NoProfile -Command "Get-Date -Format yyyyMMdd"') do set TODAY=%%d
handle.exe -s -p MyEquipApp.exe >> C:\Logs\handles_%TODAY%.log

La variable de for debe escribirse de forma distinta: %%d dentro de un archivo por lotes y %d al escribirlo directamente en el símbolo del sistema.10 Lo anterior está pensado para un archivo por lotes, así que si se pega tal cual en el símbolo del sistema no funcionará. Para probarlo directamente, cambie %%d por %d. Como la observación periódica se ejecutará desde el Programador de tareas, en el uso real se emplea la forma del archivo por lotes. Este es el punto que se confunde fácilmente con el %date:~0,4% del principio (que usa un solo % en ambos casos).

Si se añade la salida de -s (una agrupación por tipo como Event: 1523, File: 88, etc.) mediante el Programador de tareas cada hora, incluso en un PC de equipo al que solo se puede acceder de forma remota se obtienen cifras concretas de «cuántos handles de cada tipo aumentan al día». En cuanto se conoce el tipo, los sospechosos se reducen de golpe: Event sugiere eventos sin liberar, File sugiere archivos sin cerrar, Thread sugiere handles abandonados tras la finalización de un subproceso, y así sucesivamente.

Por cierto, la opción -c permite cerrar a la fuerza un handle indicado, pero la propia documentación oficial advierte que «cerrar un handle puede desestabilizar la aplicación o el sistema».2 Incluso como medida de emergencia para liberar un bloqueo, nuestra política es no usarlo en producción, por norma general. Una vez identificado «qué tipo tiene la fuga», el procedimiento para determinar «qué código la reservó» continúa en «Investigación de fallos por funcionamiento continuo en cámaras industriales - Parte de fuga de handles» y «Sentar las bases de pruebas de casos anómalos con Application Verifier».

6. VMMap ── cómo desglosar el aumento continuo de Private Bytes

Los handles se mantienen estables, pero solo Private Bytes sigue aumentando ── en ese momento es cuando se abre VMMap. Es una herramienta que analiza la memoria virtual y física (el conjunto de trabajo) de un proceso, y muestra la memoria virtual comprometida desglosada por tipo.5 Al iniciarla y seleccionar el proceso objetivo, aparece un resumen codificado por colores en la parte superior y un mapa de memoria detallado en la parte inferior. Las categorías principales se interpretan así:

Categoría Contenido Culpable típico cuando sigue aumentando
Image El propio EXE/DLL Carga de DLL de complementos que nunca se descarga
Heap Montón nativo (new/malloc/HeapAlloc) Fugas de liberación en código C/C++, SDK del equipo, interoperabilidad
Managed Heap Montón de GC de .NET Fugas de referencias administradas (controladores de eventos, etc.)
Private Data Reserva directa mediante VirtualAlloc, etc. Búferes de fotogramas de imagen, búferes internos del SDK
Stack Pila de subprocesos Subprocesos creados sin cesar
Shareable / Mapped File Memoria compartida, archivos mapeados Fugas de liberación de secciones en la comunicación entre procesos

Los pasos son los siguientes cuatro:

  1. Ejecutar VMMap como administrador. Justo después de iniciarse aparece el cuadro de diálogo de selección de proceso; seleccione el proceso objetivo y pulse OK
  2. Observar la tabla de resumen de la parte superior. Las filas corresponden al Type de la tabla anterior (Image / Heap / Managed Heap / Private Data / Stack…) y las columnas a tamaños como Size o Committed. Lo importante es anotar los valores en este momento, o exportarlos desde el menú File para conservarlos
  3. Repetir un número fijo de veces la operación problemática (un ciclo de medición del equipo, abrir y cerrar una pantalla, etc.)
  4. Actualizar la instantánea con F5 (Refresh) y comparar con los valores anotados en el paso 2. Al hacer clic en la fila del Type que ha aumentado, aparece en la parte inferior la lista de esa región

El patrón de uso es: «actualizar la instantánea con F5 mientras se repite la operación problemática, y observar qué categoría aumenta». Como VMMap admite la comparación de instantáneas, la visualización en línea de tiempo y la exportación de resultados5, se puede obtener en el sitio una evidencia como «tras 100 mediciones, Heap aumentó 40 MB y Managed Heap se mantuvo estable». Una vez decidido el terreno, entra en juego la herramienta especializada: si es Managed Heap, la investigación del lado de .NET (véase «Identificar la «lentitud» con PerfView y dotnet-trace»); si es Heap/Private Data, la investigación del lado nativo (Application Verifier o análisis de volcados). Sospechar directamente del GC sin hacer antes esta separación, y perder así varios días, es el desvío más habitual en aplicaciones de equipos con configuración mixta de .NET y SDK nativo.

En procesos de 32 bits, la fragmentación también es objeto de observación. La vista Fragmentation View muestra la dispersión de los espacios libres del espacio de direcciones, y se puede visualizar un estado en el que el total de Free suma varios cientos de MB pero el mayor bloque contiguo libre (Largest) apenas llega a unas decenas de MB. «Debería haber memoria libre, pero da OutOfMemory» o «solo falla la reserva de búferes de imagen grandes» suele deberse a esto, y sirve como fundamento documental para las medidas correctivas (pasar a 64 bits, rediseñar la reutilización de búferes).

Cuando lo sospechoso no es un proceso concreto sino la memoria de todo el sistema operativo (falta memoria aunque ningún proceso parece haber engordado), se cambia a RAMMap, que muestra por pestañas el uso total de la memoria física. Como se puede ver incluso el uso de la caché de archivos, los controladores y el kernel, es ahí donde se busca «un culpable ajeno a la aplicación».6

7. Caso práctico ── cómo diagnosticar «el PC del equipo se vuelve lento cada viernes»

Diagnosticar de forma real el PC del equipo mencionado al principio, con las herramientas vistas hasta ahora, queda así. Como la operación consiste en reiniciar el lunes por la mañana, el viernes es el «quinto día de funcionamiento». Es decir, la hipótesis inicial es que hay algo que aumenta en proporción al tiempo.

  1. Alrededor del miércoles, dejar Process Explorer abierto y preparar las columnas. Se añaden Handle Count, USER Objects, GDI Objects y Private Bytes, y se registra el valor del proceso objetivo. Al mismo tiempo, se registra en el Programador de tareas un registro por hora de handle -s -p aplicación_objetivo.exe (capítulo 5).
  2. Al día siguiente, observar la tendencia. En este caso, Handle Count aumentó unos 20.000 en un día, y en el registro por tipo los handles de Event crecían de forma monótona. Private Bytes y GDI/USER se mantenían prácticamente estables. En este punto ya se puede acotar el problema a una «fuga de liberación de objetos del kernel (eventos)».
  3. Ver el objeto real en la vista Handles. Al ordenar por Type la vista Handles del panel inferior, aparecen decenas de miles de Event sin nombre. Como no tienen nombre, no se pueden rastrear con Find Handle, pero basta con conocer el tipo y el ritmo de aumento. A partir de la correspondencia con el ciclo de medición (en este caso, 2 por cada sondeo del equipo), se formuló la hipótesis de una fuga de liberación de eventos de espera de la biblioteca de comunicaciones, que se confirmó mediante revisión de código. Si se quiere identificar con herramientas el punto exacto de reserva, aquí es donde entran Application Verifier o !htrace.
  4. Si Private Bytes hubiera estado aumentando, en lugar del paso 3 se desglosa con VMMap (capítulo 6), y se bifurca hacia la investigación nativa si es Heap o hacia .NET si es Managed Heap.
  5. Si todas las cifras se mantienen estables y solo hay cuelgues, se observa la pila en la pestaña Threads (capítulo 4) para identificar en qué se está esperando.

El punto clave es asegurar, antes de la corrección, la evidencia de «la pendiente del gráfico». Si tras la corrección se repite la misma medición y se demuestra que la pendiente se ha vuelto cero, se puede informar «se ha solucionado» con cifras concretas. En los problemas de funcionamiento continuo donde la reproducción tarda varios días, preparar esta medición es, en sí mismo, el núcleo de la investigación.

8. Uso en PC de producción y precauciones operativas ── Sysinternals Live, el EULA y los símbolos sin conexión

Todas las herramientas de Sysinternals son ejecutables independientes que no requieren instalación: basta con llevar el ZIP en una memoria USB para que funcionen tal cual. En la primera ejecución aparece un cuadro de diálogo de aceptación del EULA, así que en ejecuciones desatendidas o desde scripts la aceptación se indica explícitamente con el modificador /accepteula. En entornos donde se dispone de red, el servicio Sysinternals Live permite ejecutarlas directamente sin descargarlas, mediante una URL como https://live.sysinternals.com/procexp.exe o una ruta UNC como \\live.sysinternals.com\tools\<nombre_de_la_herramienta>.7 Es la vía más rápida cuando se necesita «verlo ahora mismo, en esta única máquina».

En un PC de equipo sin conexión, el obstáculo son los símbolos (no se puede usar la visualización de pila del capítulo 4). Hay dos soluciones: (1) resolver los símbolos para la misma compilación del sistema operativo en una máquina de desarrollo con acceso a internet, copiar la caché local (C:\Symbols) completa al PC del equipo y dejar la ruta de símbolos apuntando solo a esa carpeta local. (2) renunciar al análisis de pila y, en el lugar, limitarse a capturar volcados (ProcDump) y registrar cifras, para luego llevárselos y analizarlos en la máquina de desarrollo. Lo más seguro es la opción (2); el modo de capturar volcados está recopilado en «Introducción a la recopilación de volcados de fallos de Windows».

Por último, un aspecto operativo. La observación con Process Explorer o VMMap tiene bajo impacto y bajo riesgo, pero las operaciones de intervención, como Kill/Suspend de procesos, Kill de subprocesos, Close Handle o handle -c, deben prohibirse en principio en producción. Al igual que con ProcMon en la entrega anterior, lo más seguro es someter la ejecución al mismo proceso de aprobación que cualquier trabajo de cambio habitual, y decidir de antemano «cuándo, quién y qué se va a observar, y qué no se va a manipular».

9. Reglas prácticas (tabla de decisión)

Síntoma Herramienta a usar Dónde mirar
Cada vez va más lento / se vuelve inestable en unos días Process Explorer Tendencia de las columnas Handle Count / USER/GDI Objects / Private Bytes (capítulo 5)
No se puede eliminar o reemplazar el archivo Process Explorer / handle.exe Búsqueda de ruta con Find Handle or DLL (Ctrl+F) → proceso que lo retiene (capítulo 3)
Cuelgue / sin respuesta Process Explorer Propiedades → pestaña Threads → pila de subprocesos (requiere símbolos, capítulo 4)
Private Bytes sigue aumentando VMMap Cuál de Heap / Managed Heap / Private Data está aumentando (capítulo 6)
Falta memoria aunque ningún proceso parece haber engordado RAMMap Uso de la memoria física con Use Counts/File Summary6
Se bloquea / falla por una excepción ProcDump + WinDbg Recopilación de volcadosWinDbg + SOS
Dónde se consume la CPU / GC de .NET PerfView / dotnet-trace Investigación cuantitativa de la «lentitud»
Secuencia temporal de operaciones (qué archivo, cuándo, en qué orden) Process Monitor Artículo anterior

10. Resumen

  • Mientras que ProcMon registra el «historial de operaciones», Process Explorer / Handle / VMMap son herramientas que observan «el estado en este preciso instante». En la investigación de aplicaciones de funcionamiento continuo, se necesitan ambos enfoques.
  • «No puedo eliminar el archivo» se resuelve en segundos con Find Handle or DLL (Ctrl+F); «se quedó colgado» se orienta con la pila de la pestaña Threads. Leer la pila requiere configurar previamente dbghelp.dll (en una ubicación junto con symsrv.dll) y la ruta de símbolos; ese dbghelp.dll se obtiene instalando Debugging Tools for Windows.
  • Solo se puede buscar por nombre los objetos que tienen nombre. Es lo más potente para algo con nombre, como un archivo, pero los eventos y mutexes sin nombre no aparecen en la búsqueda. Empezar la investigación de una fuga de handles «buscando al culpable con Ctrl+F» acaba en fracaso; cambie a la agrupación por tipo (handle -s) y a ordenar la vista Handles por Type.
  • «Cada vez va más lento» se examina añadiendo las columnas Handle Count, USER/GDI Objects y Private Bytes, y observando la tendencia. Con un registro periódico de handle -s, se pueden obtener cifras incluso en un PC de equipo donde no se puede abrir la GUI.
  • El aumento de Private Bytes se separa con VMMap en Heap (nativo) / Managed Heap (.NET) / Private Data antes de pasar a la herramienta especializada. En procesos de 32 bits, sospeche también de la fragmentación.
  • El cierre forzado mediante handle -c o Close Handle es, tal como advierte la documentación oficial, una fuente de inestabilidad. En producción, limítese a la observación; si hace falta intervenir, hágalo siempre a través del proceso de aprobación.
  • Las herramientas son independientes y fáciles de llevar; con Sysinternals Live incluso se pueden ejecutar directamente. En entornos sin conexión, se compensa con una caché previa de símbolos o llevándose los volcados para analizarlos después.

Artículos relacionados

Áreas de consultoría relacionadas

KomuraSoft LLC se ocupa de la investigación de fugas en aplicaciones de negocio y aplicaciones vinculadas a equipos que se degradan con el funcionamiento continuo, del análisis de causas de fallos de campo como cuelgues o «archivo en uso», y de la preparación de procedimientos de recopilación de evidencias junto con las correcciones para evitar la recurrencia.

Referencias

  1. Microsoft Learn, Process Explorer - Sysinternals. Sobre que Process Explorer muestra los handles abiertos y las DLL cargadas / los archivos mapeados en memoria de un proceso en dos paneles (modo handle / modo DLL), que permite buscar procesos con un handle o una DLL determinados, que es útil para rastrear problemas de versión de DLL y fugas de handles, que al usar un servidor de símbolos se necesita symsrv.dll en la misma ubicación que dbghelp.dll, que se puede ejecutar directamente desde Sysinternals Live, y que los requisitos de sistema son Windows 11 o posterior en clientes y Windows Server 2016 o posterior en servidores.  2 3 4 5 6 7

  2. Microsoft Learn, Handle - Sysinternals. Sobre que handle.exe es una herramienta de línea de comandos que muestra información de los handles abiertos y requiere permisos de administrador, la búsqueda por coincidencia parcial de nombre, el uso de -a para incluir todos los tipos de handle, el filtrado por proceso con -p, la agrupación del número de handles por tipo con -s, y que -c permite cerrar handles pero está advertido de que “puede provocar inestabilidad en la aplicación o el sistema”.  2 3 4

  3. Microsoft Learn, Microsoft Public Symbol Server. Sobre que la ruta de símbolos del servidor público de símbolos de Microsoft se puede especificar con el formato srvcaché_localhttps://msdl.microsoft.com/download/symbols, y que en el almacén de descarga (caché local) solo se guardan los símbolos a los que ya se ha accedido una vez, leyéndose de forma local a partir de la segunda vez.  2

  4. Microsoft Learn, GDI Objects. Sobre que los handles GDI tienen un límite teórico de 65.536 por sesión, y que existe un límite predeterminado por proceso que se puede modificar mediante GDIProcessHandleQuota en el registro (en el rango de 256 a 65.536).  2

  5. Microsoft Learn, VMMap - Sysinternals. Sobre que VMMap es una herramienta de análisis de memoria virtual y física de un proceso, que muestra el desglose por tipo de la memoria virtual comprometida y la memoria física asignada a cada tipo (working set), que admite filtrado y actualización (instantáneas), y que admite la exportación de datos y la creación de scripts mediante opciones de línea de comandos.  2 3

  6. Microsoft Learn, RAMMap - Sysinternals. Sobre que RAMMap es una herramienta que analiza el uso de la memoria física de todo el sistema operativo y muestra el uso mediante pestañas como Use Counts (agregación por tipo), Processes (conjunto de trabajo de los procesos) y File Summary (datos de archivos en RAM), y que admite guardar y cargar instantáneas.  2 3

  7. Microsoft Learn, Sysinternals. Sobre que Sysinternals Live es un servicio que permite ejecutar las herramientas sin descargarlas, que se pueden ejecutar directamente mediante la URL live.sysinternals.com/ o la ruta \\live.sysinternals.com\tools\, y que en live.sysinternals.com se puede consultar la lista de herramientas.  2

  8. Microsoft Learn, Debugging Tools for Windows SDK and WDK. Sobre que Debugging Tools for Windows está incluido en el Windows SDK y el WDK, que se puede instalar solo el depurador ejecutando el instalador del Windows SDK, seleccionando únicamente “Debugging Tools for Windows” en la lista de funciones y desmarcando todo lo demás, y que la fuente del instalador es el Windows SDK 2

  9. Microsoft Learn, Install WinDbg. Sobre que WinDbg se puede usar para el análisis de volcados de fallos y la depuración en modo usuario y modo kernel, que existen los métodos de instalación mediante instalador directo, a través de Microsoft Store, o con winget install Microsoft.WinDbg, y que la versión clásica de WinDbg (classic) está incluida en Debugging Tools for Windows. 

  10. Microsoft Learn, for. Sobre que dentro de un archivo por lotes se escribe %%variable, mientras que al ejecutarlo directamente en el símbolo del sistema se escribe %variable, y sobre que for /f puede analizar la salida de un comando. 

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

Si ya existe el Administrador de tareas, ¿por qué molestarse en usar Process Explorer?
Porque el Administrador de tareas no muestra «qué proceso tiene abierto qué archivo u objeto» ni «en qué código está detenido cada subproceso en este momento». Process Explorer permite ver la lista de handles y DLL de cada proceso, buscar handles por nombre (Ctrl+F) e incluso mostrar la pila de subprocesos, lo que sitúa la investigación de «no puedo eliminar el archivo» o «se quedó colgado» en un nivel completamente distinto al del Administrador de tareas. Si además se añaden columnas de número de handles y de objetos USER/GDI, también sirve como herramienta de monitorización de fugas. Al activar Replace Task Manager en el menú Options, las llamadas al Administrador de tareas se sustituyen por Process Explorer, así que, en la práctica, conviene hacer esa sustitución en las máquinas dedicadas a la investigación.
¿Cerrar un handle con la opción -c de handle.exe libera de inmediato el bloqueo de un archivo?
Técnicamente es posible, pero en un entorno de producción, por norma general, no debe hacerse. La propia documentación oficial advierte de que «cerrar un handle puede desestabilizar la aplicación o el sistema». Como se le arrebata el handle al proceso desde fuera, ignorando su estado interno, puede darse el peor de los accidentes: que ese proceso, al usar más adelante el mismo handle, termine apuntando a otro objeto distinto y funcione mal (la reutilización del valor del handle). El camino correcto es identificar el proceso que lo retiene y terminarlo de la forma adecuada. Si el contexto es querer reemplazar un exe o DLL en uso, considere una solución de diseño como Restart Manager.
Private Bytes sigue aumentando sin parar. ¿Qué debo hacer primero?
El primer paso es abrir el proceso objetivo con VMMap y ver en qué categoría está el aumento. Si aumenta Heap, hay una fuerte sospecha de fuga nativa mediante malloc/new/HeapAlloc, y los sospechosos son el SDK del proveedor del equipo o código de C++/CLI e interoperabilidad. Si aumenta Managed Heap, se trata de un problema del montón administrado de .NET, así que se pasa a investigar referencias que el GC no puede recolectar (por ejemplo, controladores de eventos que no se han dado de baja). Si aumenta Private Data (reserva directa con VirtualAlloc), sospeche de código o de un SDK que reserve bloques grandes, como búferes de imagen. Una vez hecha esta separación, avanzar hacia la herramienta especializada correspondiente (WinDbg, PerfView, etc.) evita que la investigación se pierda.
En un PC de equipo sin conexión, la pila de la pestaña Threads se ve como una lista de direcciones ilegible. ¿Qué debo hacer?
Se debe a que no se pueden descargar los símbolos (PDB), y la solución se reduce a dos opciones: «llevar los símbolos» o «llevarse el volcado». Para llevar los símbolos, se resuelven una vez en una máquina de desarrollo con acceso a internet, para la misma compilación del sistema operativo y la misma configuración de la aplicación, y luego se copia la carpeta de caché local completa (por ejemplo, C:\Symbols) al PC del equipo, dejando la ruta de símbolos apuntando solo a esa carpeta local. Para llevarse el volcado, es más seguro capturarlo durante el cuelgue y analizarlo con WinDbg en la máquina de desarrollo, y esta opción también es la más adecuada cuando se quiere leer con precisión la pila de una aplicación administrada. Es una condición previa fundamental conservar el PDB de la aplicación propia para cada compilación.
¿Hay algún problema en instalar Process Explorer o VMMap en un PC de producción o de equipo?
Ambas son herramientas ejecutables independientes que no requieren instalación y funcionan sin registrarse en el registro de Windows ni residir como servicio, por lo que la barrera para llevarlas es baja. En la primera ejecución hace falta aceptar el EULA, y si se usan desde un script, la aceptación se puede indicar explícitamente con el modificador /accepteula. En un entorno con red disponible, también se pueden ejecutar directamente desde Sysinternals Live (https://live.sysinternals.com) sin necesidad de descargarlas. Sin embargo, aunque la observación sea de bajo riesgo, las operaciones de «intervención», como Kill/Suspend de procesos, Kill de subprocesos o el cierre forzado de handles, están directamente ligadas a accidentes, así que en producción limítese a observar y registrar, y llévelas a cabo dentro del proceso habitual de aprobación de trabajos.

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog