Typical Java Crash Scenarios with Sample Code
This article examines typical Java application failure scenarios—including heap OOM, memory leaks, CPU spikes, thread leaks, deadlocks, stack overflows, and blocked threads—providing concise code examples and practical diagnostic tips for root cause analysis.
Java programs run on a garbage‑collected runtime and often allocate a large heap at startup; combined with JIT optimizations they can be as fast as native C++ code, but issues such as memory leaks or crashes can be harder to pinpoint without tools like JFR.
1. Heap Space Overflow (OOM)
An OutOfMemoryError is usually caused by a memory leak that makes GC pauses longer and heap usage keep rising. The following demo continuously inserts data into a HashMap that is a GC root, eventually exhausting the heap.
import java.util.HashMap;
public class OOMDemo {
static HashMap
myMap = new HashMap<>();
public static void start() throws Exception {
while (true) {
myMap.put("key" + counter, "Large string..." + counter);
++counter;
}
}
}2. Memory Leak
Memory leaks are conceptually similar to OOM but refer to unexpected, sustained growth of heap usage. Tools such as jmap or pmap are often needed to locate the root cause. A common leak occurs when hashCode and equals are not overridden correctly.
// leak example : created by xjjdog 2022
import java.util.HashMap;
import java.util.Map;
public class HashMapLeakDemo {
public static class Key {
String title;
public Key(String title) { this.title = title; }
}
public static void main(String[] args) {
Map
map = new HashMap<>();
map.put(new Key("1"), 1);
map.put(new Key("2"), 2);
map.put(new Key("3"), 2);
Integer integer = map.get(new Key("2"));
System.out.println(integer);
}
}3. CPU Spike
A tight infinite loop can fully consume CPU cores. The demo launches several threads that each run an endless loop.
public class CPUSpikeDemo {
public static void start() {
new CPUSpikerThread().start();
new CPUSpikerThread().start();
new CPUSpikerThread().start();
new CPUSpikerThread().start();
new CPUSpikerThread().start();
new CPUSpikerThread().start();
System.out.println("6 threads launched!");
}
}
public class CPUSpikerThread extends Thread {
@Override
public void run() {
while (true) {
// Just looping infinitely
}
}
}4. Thread Leak
Creating threads without ever terminating them quickly exhausts system resources. The following code continuously spawns new threads that sleep forever.
public class ThreadLeakDemo {
public static void start() {
while (true) {
new ForeverThread().start();
}
}
}
public class ForeverThread extends Thread {
@Override
public void run() {
// Put the thread to sleep forever, so they don't die.
while (true) {
try {
Thread.sleep(10 * 60 * 1000);
} catch (Exception e) {}
}
}
}5. Deadlock
Deadlocks are rare but severe; they occur when two threads hold locks the other needs. The demo shows two synchronized methods calling each other, causing a circular wait.
public class DeadLockDemo {
public static void start() {
new ThreadA().start();
new ThreadB().start();
}
}
public class ThreadA extends Thread {
@Override
public void run() { CoolObject.method1(); }
}
public class ThreadB extends Thread {
@Override
public void run() { HotObject.method2(); }
}
public class CoolObject {
public static synchronized void method1() {
try { Thread.sleep(10 * 1000); } catch (Exception e) {}
HotObject.method2();
}
}
public class HotObject {
public static synchronized void method2() {
try { Thread.sleep(10 * 1000); } catch (Exception e) {}
CoolObject.method1();
}
}6. Stack Overflow
A recursive call without a termination condition overflows the JVM stack. The demo simply calls start() recursively.
public class StackOverflowDemo {
public void start() { start(); }
}The stack size can be adjusted with the -Xss JVM option (e.g., -Xss128K ).
7. BLOCKED Thread
A thread in the BLOCKED state is waiting to acquire a lock, often because a request takes too long. The following example creates several threads that invoke a synchronized method which sleeps indefinitely, causing BLOCKED threads.
public class BlockedAppDemo {
public static void start() {
for (int i = 0; i < 10; ++i) {
new AppThread().start();
}
}
}
public class AppThread extends Thread {
@Override
public void run() { AppObject.getSomething(); }
}
public class AppObject {
public static synchronized void getSomething() {
while (true) {
try { Thread.sleep(10 * 60 * 1000); } catch (Exception e) {}
}
}
}Frequent BLOCKED states indicate that the application is too slow; increasing the thread pool size (e.g., Tomcat's maxThreads) may help if CPU resources are still available.
End
The examples above cover the most common Java failure patterns; diagnosing them usually requires deep knowledge of the runtime and appropriate tooling such as jstack , fastthread, or custom monitoring utilities.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
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.