Las fugas de memoria están entre los errores más frustrantes de diagnosticar: tu app va lenta, el ventilador se acelera y no sabes qué proceso es el culpable ni por qué. Esta guía recorre un enfoque sistemático para encontrar fugas de memoria en macOS con ProcXray.
Respuesta rápida
Para depurar fugas de memoria en macOS, primero confirma un crecimiento sostenido de la memoria que no se recupera, luego identifica el proceso que tiene la fuga, valida el contexto de lanzamiento y el entorno, y correlaciona con señales de descriptores de archivo o de bibliotecas. Usa ProcXray para una clasificación rápida y los perfiladores de cada plataforma para llegar a la causa raíz a nivel de código.
Reconocer los síntomas
Antes de recurrir a una herramienta, confirma que tienes una fuga de memoria y no un uso elevado legítimo:
- Memoria que aumenta de forma constante con el tiempo (no solo un pico durante una tarea)
- La memoria no baja después de que la app queda inactiva
- El uso de swap del sistema crece aunque hayas cerrado otras apps
- El proceso nunca libera memoria incluso después de completar el trabajo que provocó el crecimiento
Paso 1: identificar el proceso que tiene la fuga
Abre ProcXray y ordena por Memory (descendente). Busca:
- Un proceso cuya columna de memoria no para de subir
- Un proceso con un uso de memoria inesperadamente alto para lo que hace (p. ej., un daemon en segundo plano usando 2 GB)
El gráfico de memoria en tiempo real de ProcXray en la pestaña History del panel de detalles se actualiza continuamente. Fija un proceso sospechoso y observa la línea de tendencia: una fuga se muestra como una pendiente ascendente constante que nunca se aplana.
Paso 2: comprobar qué es realmente el proceso
Haz clic en el proceso sospechoso. En la pestaña General encontrarás:
- La ruta completa del ejecutable (útil cuando el nombre del proceso es ambiguo, como
nodeopython3) - Los argumentos de línea de comandos (te dicen qué script o servidor se está ejecutando)
- El directorio de trabajo
- El proceso padre (te dice qué lo lanzó)
Un proceso node en segundo plano que devora 3 GB no sirve de nada sin saber que es node /Users/me/myapp/server.js.
Paso 3: inspeccionar las variables de entorno
Cambia a la pestaña Environment. Las fugas de memoria en apps de Node.js, Python o Ruby a veces se deben a una mala configuración del entorno:
NODE_ENV=developmentactivando un middleware de depuración pesado en producción- Un ORM configurado para registro detallado que mantiene los objetos de consulta en memoria
- Una biblioteca de caché configurada sin política de expulsión
Copia el entorno como JSON y revisa los tamaños de caché, los límites de pool o las flags de depuración.
Paso 4: comprobar los descriptores de archivo abiertos
Las fugas de memoria en servidores a menudo van acompañadas de fugas de descriptores de archivo: el proceso abre archivos, sockets o pipes y nunca los cierra. Cambia a la pestaña Connections en ProcXray para ver:
- Todos los archivos abiertos
- Todos los puertos en escucha
- Todas las conexiones de red activas
Un servidor con 10 000 descriptores de archivo abiertos cuando debería tener 50 es una señal clara de una fuga de recursos relacionada.
Paso 5: comprobar las bibliotecas cargadas
A veces la fuga está en una biblioteca nativa. La pestaña Modules de ProcXray lista todas las bibliotecas dinámicas que el proceso ha cargado. Compáralas con las dependencias conocidas de tu app: una versión inesperada de una biblioteca, o una que no debería estar ahí en absoluto, puede explicar un comportamiento inusual.
Paso 6: reproducir y confirmar
Una vez que tengas un sospechoso (un proceso concreto + una ruta de código), reproduce la fuga deliberadamente:
- Anota la memoria actual del proceso en ProcXray
- Desencadena la operación que sospechas que causa la fuga (p. ej., subir un archivo, ejecutar una consulta, llamar a una API)
- Observa la tendencia de memoria en ProcXray
- Espera a que la app quede inactiva
- Si la memoria no vuelve al nivel de partida, has confirmado la ruta de la fuga
Paso 7: análisis en profundidad con herramientas de plataforma
ProcXray te da el qué y el dónde. Para el porqué dentro de tu código, usa herramientas específicas de cada plataforma:
Para apps nativas en Swift/Objective-C:
leaks <PID> # Apple's built-in leak detector
malloc_history <PID> # Allocation history
O usa el Memory Graph Debugger de Xcode para obtener un árbol de llamadas visual.
Para Node.js:
node --inspect server.js
# Then use Chrome DevTools Memory tab or clinic.js
Para Python:
from memory_profiler import profile
@profile
def my_function():
...
Culpables habituales
| Causa | Señal |
|---|---|
| Caché sin límites | La memoria crece de forma proporcional a las peticiones |
| Listener de eventos no eliminado | La memoria crece con las interacciones de la interfaz |
| Fuga en biblioteca nativa | La pestaña Modules muestra una discrepancia de versión |
| Descriptores de archivo sin cerrar | La pestaña Connections muestra miles de archivos abiertos |
| Nodos del DOM retenidos | El proceso del navegador crece pese a navegar a otra página |
Resumen
- Ordena por memoria en ProcXray e identifica el proceso que crece
- Usa la pestaña General para confirmar qué es el proceso y cómo se lanzó
- Comprueba las variables de entorno por si hay una mala configuración
- Comprueba la pestaña Connections por si hay fugas de descriptores de archivo
- Reproduce la ruta de la fuga
- Pasa el relevo a Xcode Memory Debugger, clinic.js o memory_profiler para el análisis a nivel de código
Descargar ProcXray → para empezar tu investigación: gratis, macOS Sonoma+.
Preguntas frecuentes
¿Cómo distingo una fuga de memoria de un pico de memoria normal?
Un pico suele estabilizarse o bajar después de que la carga de trabajo termina. Una fuga aparece normalmente como un crecimiento persistente a lo largo de operaciones repetidas, sin volver al nivel de partida durante los periodos de inactividad.
¿Por qué comprobar los descriptores de archivo al depurar fugas de memoria?
Las fugas de recursos suelen darse juntas. Un proceso que abre continuamente sockets o archivos sin cerrarlos puede mostrar tanto crecimiento de descriptores como presión de memoria.
¿Qué herramienta debo usar después de encontrar el proceso que tiene la fuga?
Usa perfiladores específicos del lenguaje o la plataforma: Xcode Memory Graph para Swift/Objective-C, DevTools/clinic.js para Node.js, y flujos de trabajo con memory_profiler o tracemalloc para Python.