Medium java spring

How do ThreadLocal, static collections and lingering references cause memory retention?

The 30 second answer

A ThreadLocal value lives as long as its thread, and pool threads never die, so a value I forget to remove stays forever and can even leak into the next request. Static maps and caches without eviction grow without limit, and listeners that are never unregistered keep objects alive. I confirm it with a heap dump and look at what holds the biggest retained size.

Thread-local values live as long as the thread does. In a thread pool, threads never die, so a value you forget to remove() stays forever and can leak to the next request. Static maps and caches without eviction grow without limit, and listeners that are never unregistered keep objects alive. I confirm with a heap dump (jcmd <pid> GC.heap_dump) and look at what holds the biggest retained size. Follow-up: How do you use ThreadLocal safely? (try { tl.set(x); ... } finally { tl.remove(); }, or scoped values in newer Java.)

Sources (3)
  1. ThreadLocal Javadoc
  2. Troubleshooting memory leaks (Java 21)
  3. jcmd