Detección y corrección de fugas de memoria
Identifique patrones habituales de fugas de memoria (colecciones estáticas, listeners y cachés) y corríjalos.
Detección y corrección de fugas de memoria es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
¿Qué es una fuga de memoria en Java?
Una fuga de memoria en Java ocurre cuando los objetos ya no son necesarios, pero siguen siendo fuertemente alcanzables, lo que impide que el GC los recupere. El heap crece hasta que se lanza un OutOfMemoryError.
Acumulación en una colección estática
Un campo estático que contiene una colección en crecimiento es una fuga clásica. Los objetos que se añaden pero nunca se eliminan permanecen vivos durante toda la vida de la aplicación.
public class Cache {
// LEAK: static list grows forever if items are never removed
private static final List<Object> items = new ArrayList<>();
public static void add(Object o) { items.add(o); }
// Fix: add a remove() method or use a bounded cache
}Listeners de eventos no registrados
Registrar un listener sin eliminarlo nunca mantiene vivos tanto el listener como cualquier objeto al que haga referencia. Anule siempre el registro de los listeners cuando ya no sean necesarios.
// Leak:
sensor.addListener(new DataLogger());
// Fix:
DataLogger logger = new DataLogger();
sensor.addListener(logger);
// ... when done:
sensor.removeListener(logger);Variables ThreadLocal no limpiadas
En los pools de subprocesos, los valores de ThreadLocal sobreviven entre tareas porque los subprocesos se reutilizan. Si no se borran, los datos de una tarea se filtran a las tareas posteriores que se ejecuten en el mismo subproceso.
private static final ThreadLocal<MyContext> CTX = new ThreadLocal<>();
// Always clean up after each task:
try {
CTX.set(new MyContext(requestId));
doWork();
} finally {
CTX.remove(); // prevents leak in pooled threads
}Fugas de classloaders en aplicaciones con despliegue en caliente
En los contenedores de servlets, cada despliegue utiliza un classloader nuevo. Si alguna clase mantiene una referencia estática a una clase del classloader antiguo, todo el classloader antiguo (y todas sus clases) no se puede recopilar mediante el GC.
Detección de fugas con volcados de memoria heap
Realice un volcado de memoria heap con jmap -dump:format=b,file=heap.hprof <pid> y, después, ábralo en Eclipse MAT o VisualVM para encontrar los objetos retenidos más grandes y sus raíces de GC.
// Take a heap dump:
jmap -dump:live,format=b,file=heap.hprof $(jps | grep MyApp | cut -d" " -f1)
// Or trigger on OOM:
// -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heap.hprofEclipse Memory Analyzer (MAT)
El informe "Leak Suspects" de MAT identifica automáticamente los objetos con una gran cantidad de memoria heap retenida y muestra la ruta desde las raíces de GC. Comience con la vista "Dominator Tree" para encontrar los principales responsables.
Uso de WeakReference para evitar fugas
Envuelva los objetos almacenados en caché o los listeners en WeakReference. El GC puede reclamarlos cuando hay presión de memoria. Compruebe siempre si el resultado de get() es null.
Map<String, WeakReference<Image>> imageCache = new HashMap<>();
imageCache.put("logo", new WeakReference<>(loadImage("logo.png")));
Image logo = imageCache.get("logo") != null ? imageCache.get("logo").get() : null;
if (logo == null) logo = reload("logo.png"); // re-load if GCedCachés limitadas con LinkedHashMap LRU
Sobrescriba removeEldestEntry en un LinkedHashMap para limitar el tamaño de la caché y expulsar automáticamente la entrada menos utilizada recientemente.
Map<String, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
protected boolean removeEldestEntry(Map.Entry<String, String> e) {
return size() > 100; // evict when over 100 entries
}
};Perfilado de asignaciones con Java Flight Recorder
JFR (Java Flight Recorder) captura perfiles de asignación con una sobrecarga mínima. Actívelo con -XX:StartFlightRecording y analícelo con JDK Mission Control.
// Start a 60-second JFR recording:
java -XX:StartFlightRecording=duration=60s,filename=rec.jfr MyApp
// Or via jcmd:
jcmd <pid> JFR.start duration=60s filename=rec.jfrCorrección de fugas: lista de comprobación
Compruebe lo siguiente: colecciones estáticas, listeners no registrados, ThreadLocals en pools, fugas de conexiones o streams (use try-with-resources), referencias de clases internas a objetos externos y cachés sin expulsión.
Comprobación rápida
¿Qué opción de la JVM realiza automáticamente un volcado de memoria heap cuando se lanza OutOfMemoryError?
Resumen
Fuentes habituales de fugas en Java: colecciones estáticas, listeners no registrados, ThreadLocals en pools y cachés sin límite. Detecte las fugas con volcados de memoria heap y MAT. Corríjalas con WeakReferences, estructuras limitadas y eliminando siempre las referencias cuando ya no sean necesarias.
Preguntas frecuentes
¿La lección «Detección y corrección de fugas de memoria» es gratis?
Sí — el texto completo de «Detección y corrección de fugas de memoria» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Detección y corrección de fugas de memoria»?
Identifique patrones habituales de fugas de memoria (colecciones estáticas, listeners y cachés) y corríjalos. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Detección y corrección de fugas de memoria»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Regiones del heap de la JVM y ciclo de vida de los objetos
- Algoritmos de GC: Serial, G1, ZGC y Shenandoah
- Detección y corrección de fugas de memoria
- Indicadores de ajuste del GC y creación de perfiles con JVisualVM