Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To diagnose a suspected Spring Boot memory leak, compare post-GC heap and class counts under a repeatable workload, then inspect a heap dump for the reference path keeping growing objects alive. Fix the long-lived owner only when the evidence identifies it: that may be an unintended static reference, a singleton field, an unbounded cache, a listener, or thread-local state. Changing a bean to prototype scope by itself does not remove a reference or prove a leak is fixed.

What counts as a memory leak in a Spring Boot application?

A Java memory leak is unintended retention: an object remains reachable through references even though the application no longer needs it. The garbage collector cannot collect reachable objects. Oracle defines the mechanism as an application unintentionally holding references to objects or classes, preventing garbage collection (Troubleshoot Memory Leaks, Java SE 26).

A large heap, high allocation rate, or temporary rise in memory use does not alone establish a leak. First establish that the live heap or a population of objects keeps growing after garbage collection under comparable workload and collection conditions. Also determine whether the growth is in Java heap or process/native memory; a heap dump helps with Java objects, but does not account for every kind of native or off-heap use.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do I diagnose a memory leak in a Spring Boot application?

  1. Record a baseline. Note the application build, Spring Boot and Framework versions, JDK version, heap settings, workload shape, and whether the suspected growth is Java heap or process/native memory. Repeat a stable workload and compare live heap after collection rather than comparing unrelated peaks.
  2. Track growing classes. At consistent intervals, run jcmd <pid> GC.class_histogram and compare class counts and bytes. Oracle recommends repeated histograms to reveal trends. A histogram narrows the search; it does not show why objects remain reachable.
  3. Capture a heap dump. Run jcmd <pid> GC.heap_dump filename=heapdump.hprof. Check the exact syntax and availability against the JDK running in production. Oracle also documents -XX:+HeapDumpOnOutOfMemoryError to preserve a dump when an OutOfMemoryError occurs; it does not prevent the failure.
  4. Trace objects to their owners. In a heap-analysis tool, select representative objects from the growing population and inspect paths to GC roots. Follow each path to the first application-controlled owner. If you suspect a static reference, verify the actual static field and the objects reachable from its value; the mere presence of static fields is not evidence of a leak.
  5. Use JFR when timing or allocation patterns matter. Oracle documents JFR recordings with heap statistics for observing live objects and top growers. Recording GC-root paths can help identify leak paths, but it takes time and adds diagnostic overhead, so enable it for a suspected leak with an appropriate recording configuration.
  6. Check the lifecycle contract. Inspect bean definitions and injection sites for state that belongs to a request or operation but is held by a long-lived bean. Check caches, listeners, registries, static fields, and thread-local values for retaining paths, not just for their existence.
  7. Repeat the same capture after the fix. Run the same workload and compare post-GC heap, histograms, and, if used, JFR or heap-dump evidence. A fix is supported when the suspect retained population stops growing under that comparison—not merely because a restart cleared memory or the heap limit was raised.
Evidence What it helps answer Limitation
jcmd <pid> GC.class_histogram at repeated intervals Which classes’ counts or sizes are trending upward? Shows a trend clue, not the reference path.
jcmd <pid> GC.heap_dump filename=heapdump.hprof Which objects exist, and what references retain selected objects? Creates a snapshot that can be large and may contain sensitive application data; inspect it with a suitable heap-analysis tool.
JFR with heap statistics How do live objects and top growers change over time? Requires appropriate recording settings; deeper root-path collection takes time and has diagnostic overhead.
-XX:+HeapDumpOnOutOfMemoryError Can a heap snapshot be captured when an OOM occurs? Captures at failure time; it neither prevents the leak nor replaces trend diagnosis.

Treat heap dumps as sensitive artifacts: they can contain application data. Store, access, and share them according to your organization’s data-handling rules. Oracle’s Java SE 26 troubleshooting documentation calls heap dumps the most important data for troubleshooting memory leaks; use the documentation matching the deployed JDK because command availability and behavior vary by version.

Can a static field cause a Java memory leak?

Yes. A static field can keep an object reachable for as long as its class and class loader remain reachable. For example, a static collection that accumulates request or operation objects can retain them after those operations finish. But a static field is not inherently a leak: the deciding evidence is whether it points, directly or through other objects, to data that should no longer be retained.

Use the heap dump to confirm the field and its value graph, then decide whether the static owner has a valid application-wide lifetime. If not, remove the accidental reference or change the design so entries are bounded or cleared when their work is complete. Apply the same reasoning to singleton fields, caches, listeners, registries, and thread-local state: these are inspection targets because they can be long-lived owners, not automatic defects.

Why does my heap keep growing after garbage collection?

Post-GC growth can indicate that more objects are still reachable, but one collection or one measurement is not enough to establish a leak. Compare repeated captures after collection with a stable workload; rising counts of the same classes help identify which population to investigate. Then inspect those objects’ paths to GC roots to distinguish expected retained data from unintended retention.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If the Java heap does not explain rising process memory, investigate whether the growth is outside the Java heap rather than assuming a bean-scope problem. Heap histograms and dumps describe Java objects; they are not a complete measurement of native or off-heap memory.

Why is my prototype bean reused inside a singleton?

Spring’s singleton scope means one instance per bean definition per IoC container, not one instance for the whole JVM. Singleton is the default scope. A prototype-scoped bean is newly created each time the container is asked for that bean, but direct injection into a singleton happens when the singleton is instantiated. The singleton then holds that one injected instance; Spring does not automatically fetch a fresh prototype on every method call.

Spring’s reference explains that prototype instances are handed to the client and Spring does not manage their complete later lifecycle or invoke configured destruction callbacks for them. Client code must release expensive resources. The framework’s rule of thumb is prototype for stateful beans and singleton for stateless ones, but that is not a substitute for reviewing actual state, concurrency, object cost, and cleanup duties.

Which bean scope or lookup pattern should I use?

Need Approach Important condition
One shared, stateless service per bean definition and container Singleton scope, Spring’s default Ensure shared mutable state is intentional and safe for concurrent calls.
A new instance each time the dependency is requested Prototype scope A singleton that needs a new instance repeatedly must perform a runtime lookup through a provider/lookup pattern or method injection; direct injection captures one instance at singleton creation.
Data tied to a web request or session Request or session scope, as appropriate These web scopes require a web-aware ApplicationContext. A longer-lived bean that needs the shorter-lived dependency may use a scoped proxy.

Choose based on the operation’s required lifetime, whether it has per-request mutable state, whether the dependency must be reacquired on each call, who owns cleanup, and what the heap evidence identifies as the retaining owner. Confirm concurrency behavior and resource cleanup after changing scope or lookup behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How should I fix the leak and verify the result?

  • Remove or narrow a static/global reference when the heap graph shows it retaining objects beyond their intended lifetime.
  • Bound a cache or clear entries when they are no longer valid; verify that the cache was the retaining owner before changing its policy.
  • Unregister listeners or callbacks when their owner is finished, and clear thread-local values when work completes if they otherwise retain operation data.
  • For a scope mismatch, use a runtime provider/lookup or method injection when repeated calls need fresh prototype instances; use request/session scope and, where needed, a scoped proxy for web-bound state.
  • Manage cleanup explicitly for prototype instances that own resources, because Spring does not invoke their configured destruction callbacks after handing them to the client.

After making one evidence-based change, repeat the same workload and captures. If the suspected population still grows, inspect the new retaining paths rather than assuming that a scope change, cache adjustment, or restart solved the problem.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.