¿Por qué el código Java tiene fugas? Creamos y atrapamos fugas de memoria en 2025

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: «Romper no es construir»

\n

Cada desarrollador Java ha maldecido al menos una vez una fuga de memoria (memory leak) en su aplicación en producción. La aplicación falla con OutOfMemoryError, el servidor se reinicia, los usuarios escriben correos enojados. Pero también hay otra cara de la moneda: cómo crear una fuga de memoria en Java intencionalmente. Suena loco, pero precisamente esta pregunta (original de Stack Overflow) ha acumulado miles de visitas.

\n

¿Para qué saber esto? Para entender la mecánica del recolector de basura (GC) y los antipatrones que convierten tu código en un colador. En 2025, cuando Java 21 con hilos virtuales y Loom ya es estándar, las fugas antiguas no han desaparecido, simplemente se disfrazan bajo nuevas características.

\n

En este artículo no solo mostraremos cómo «estropear» una aplicación Java, sino que también daremos las mejores prácticas para detectar fugas en 2025. ¿Listos? ¡Allá vamos!

\n\n

Un poco de teoría: por qué Java no es «eterno»

\n

Muchos novatos creen firmemente que el recolector de basura (GC) elimina automáticamente todo lo que no se necesita. La realidad es cruel: una fuga de memoria en Java es posible si un objeto permanece alcanzable (reachable) desde las raíces del GC (GC roots), pero la aplicación ya no lo necesita.

\n

En 2025, con la llegada de los Value Objects (Project Valhalla) y el mejorado ZGC (recolector con tiempo de pausa < 1 ms), la situación de rendimiento ha mejorado, pero la lógica de las fugas sigue siendo la misma. El GC no es telépata: no sabe que olvidaste anular una referencia en un HashMap.

\n\n

Método n.º 1: Clásico — el HashMap «olvidadizo»

\n

El antipatrón más popular que pasa de artículo en artículo. Pero sin él, no se puede.

\n

Cómo funciona la fuga

\n

Colocas objetos en un HashMap (o HashSet) como claves, pero olvidas eliminarlos. Si las claves son objetos mutables que cambian su código hash después de la inserción, entonces garantizas una fuga de memoria Java.

\n\n
import java.util.HashMap;\nimport java.util.Map;\n\npublic class LeakyMapExample {\n    public static void main(String[] args) {\n        Map<StringBuilder, String> map = new HashMap<>();\n\n        for (int i = 0; i < 100_000; i++) {\n            StringBuilder key = new StringBuilder("key_" + i);\n            map.put(key, "value_" + i);\n            // "Olvidamos" eliminar — las claves cuelgan para siempre\n        }\n        System.out.println("Tamaño del mapa: " + map.size());\n        // Fuga: 100_000 objetos StringBuilder + String en el heap\n    }\n}\n
\n\n

¿Por qué es una fuga? Mientras la referencia a map esté viva, todas las claves y valores permanecen en el heap. Incluso si la lógica de la aplicación ya no usa estos datos, el GC no los tocará.

\n\n

Mejor práctica 2025

\n
    \n
  • Usa WeakHashMap si las claves son objetos temporales.
  • \n
  • Para almacenamiento en caché, usa Caffeine o Guava Cache con límites de tamaño/tiempo.
  • \n
  • Nunca uses StringBuilder como clave — solo tipos inmutables.
  • \n
\n\n

Método n.º 2: Colecciones estáticas — el asesino silencioso

\n

Los campos estáticos viven hasta que la JVM se detiene. Si almacenas datos en un static List o static Map y no los limpias, obtienes una fuga de memoria Java a nivel de clase.

\n\n
import java.util.ArrayList;\nimport java.util.List;\n\npublic class StaticLeak {\n    private static final List<byte[]> CACHE = new ArrayList<>();\n\n    public static void addData() {\n        // Cada llamada añade 10 MB a la lista estática\n        CACHE.add(new byte[10 * 1024 * 1024]);\n    }\n\n    public static void main(String[] args) throws Exception {\n        for (int i = 0; i < 1_000; i++) {\n            addData();\n            Thread.sleep(100);\n        }\n        // OutOfMemoryError es inevitable\n    }\n}\n
\n\n

<

Blogs

Book Recommendations