How to Diagnose and Prevent Java OOM Errors Before Your Service Crashes
This article explains common causes of Java OutOfMemoryError, demonstrates how to reproduce OOM with sample code, and provides step‑by‑step techniques using jmap, heap dumps, and VisualVM to locate and avoid memory leaks in backend applications.
Why Java memory management matters
Effective memory management is a key indicator of application stability and availability; improper usage can easily cause memory leaks or OutOfMemoryError (OOM).
Typical OOM causes include:
Insufficient system memory resources.
Memory leaks (unused resources not released and not reclaimed by the garbage collector).
Processing large data volumes (e.g., loading too much data into the JVM at once).
Reproducing OOM
<code>public class JVMController {
@GetMapping("/add")
public String jvmOutOfMemory() {
List<Byte[]> byteList = new ArrayList<>();
for (;;) {
byteList.add(new Byte[1024 * 1024 * 1024]);
}
}
}</code>1. OOM before the system crashes
1) Use jmap for live analysis
<code># jmap -histo:live <pid>
</code>The command prints objects that occupy the most memory.
Identify large‑memory objects (bytes column) and focus analysis on them.
2) Export a heap dump
<code># jmap -dump:format=b,file=longxia.hprof <pid>
</code>Download the dump file and open it with VisualVM for deeper inspection.
2. OOM after the system has crashed
When the JVM crashes, live analysis is impossible; you must rely on the heap dump.
1) Add JVM options at startup
<code># java -jar -Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local test-1.0-SNAPSHOT.jar
</code>Enabling -XX:+HeapDumpOnOutOfMemoryError creates a large dump file that records the entire runtime state.
Download the dump (often with ops assistance) and open it in VisualVM.
2) Launch VisualVM
<code># jvisualvm
</code>Open the downloaded OOM heap dump and continue the analysis.
VisualVM helps pinpoint the root cause of the crash.
3. Common practices to avoid OOM
Use soft and weak references appropriately so that memory‑starved objects can be reclaimed.
Release resources promptly (e.g., close I/O streams).
Avoid creating excessively large objects.
Optimize data structures for memory efficiency.
Use global and static variables cautiously.
4. Does OOM always kill the process?
OOM does not necessarily terminate the JVM; it may only affect the thread that triggered the allocation.
<code>@RestController
@RequestMapping("/jvm")
public class JVMController {
@GetMapping("/add")
public String jvmOutOfMemory() {
List<Byte[]> byteList = new ArrayList<>();
for (;;) {
byteList.add(new Byte[1024 * 1024 * 1024]);
}
}
@GetMapping("/get")
public String get() {
return "get data from java";
}
}
</code>Calling /jvm/add triggers OOM, while /jvm/get continues to respond because it does not allocate new heap memory, proving that the JVM process remains alive even after an OOM in another thread.
Thus, OOM may suspend a thread without bringing down the entire process.
Lobster Programming
Sharing insights on technical analysis and exchange, making life better through technology.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.