Tutorials Logic, IN info@tutorialslogic.com

OutOfMemoryError in Java: Causes and Fixes

What is This Error?

The OutOfMemoryError (OOM) is thrown when the JVM cannot allocate an object because it has run out of heap memory and the garbage collector cannot free enough space. This is a serious error that usually indicates a memory leak or insufficient heap configuration.

Common Causes

  • Memory leak "-- objects held in memory longer than needed
  • Loading too much data into memory at once
  • Infinite loop adding to a collection
  • Static collections holding references indefinitely
  • JVM heap size too small for the workload

Quick Fix (TL;DR)

Immediate Fix: Increase heap size (temporary fix)

Immediate Fix: Increase heap size (temporary fix)
# Increase heap size (temporary fix)
java -Xmx512m -Xms256m MyApplication

# For large applications
java -Xmx2g MyApplication

# Enable GC logging to diagnose
java -Xmx512m -verbose:gc -XX:+PrintGCDetails MyApplication

Common Scenarios & Solutions

Failure: Loading millions of records into memory

Failure: Loading millions of records into memory
// Wrong Loading millions of records into memory
List<Record> allRecords = database.findAll(); // OOM for large tables!
allRecords.forEach(r -> process(r));

Correction: Process in batches

Correction: Process in batches
// Correct Process in batches
int pageSize = 1000;
int page = 0;
List<Record> batch;
do {
    batch = database.findAll(PageRequest.of(page++, pageSize));
    batch.forEach(r -> process(r));
    batch.clear(); // Help GC
} while (batch.size() == pageSize);

// Correct Or use streaming (Spring Data)
database.streamAll().forEach(r -> process(r));

Failure: Static map grows forever never cleared

Failure: Static map grows forever never cleared
class Cache {
    // Wrong Static map grows forever "-- never cleared!
    static Map<String, Object> cache = new HashMap<>();

    static void add(String key, Object value) {
        cache.put(key, value); // Memory leak!
    }
}

Correction: Use WeakHashMap entries removed when key is GC'd

Correction: Use WeakHashMap entries removed when key is GC'd
// Correct Use WeakHashMap "-- entries removed when key is GC'd
static Map<String, Object> cache = new WeakHashMap<>();

// Correct Or use a bounded cache with eviction
static Map<String, Object> cache = Collections.synchronizedMap(
    new LinkedHashMap<>(100, 0.75f, true) {
        protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > 100; // Max 100 entries
        }
    }
);

// Correct Or use Caffeine/Guava cache with TTL
Cache<String, Object> cache = Caffeine.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .build();

Failure: Reading entire 10GB file into memory

Failure: Reading entire 10GB file into memory
// Wrong Reading entire 10GB file into memory
byte[] content = Files.readAllBytes(Paths.get("huge-file.csv")); // OOM!

Correction: Stream lines one at a time

Correction: Stream lines one at a time
// Correct Stream lines one at a time
try (Stream<String> lines = Files.lines(Paths.get("huge-file.csv"))) {
    lines.forEach(line -> processLine(line));
}

// Correct Or use BufferedReader
try (BufferedReader reader = new BufferedReader(new FileReader("huge-file.csv"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        processLine(line);
    }
}

Best Practices to Avoid This Error

  • Process data in batches - Never load entire datasets into memory
  • Use streaming APIs - Files.lines(), database streaming, etc.
  • Close resources properly - Use try-with-resources for streams and connections
  • Use bounded caches - Limit cache size with eviction policies
  • Profile with VisualVM or JProfiler - Find memory leaks before they cause OOM
  • Set appropriate heap size - Use -Xmx to set maximum heap
  • Use WeakReference for caches - Allow GC to reclaim memory when needed

Identify Which Memory Area Was Exhausted

OutOfMemoryError is a family of failures, not a single heap diagnosis. The message may point to Java heap space, GC overhead, metaspace, direct buffer memory, native thread creation, or another allocation boundary. Record the exact message, JVM options, process limits, container limits, GC logs, and workload phase before changing heap size.

For heap growth, capture a heap dump near failure and compare retained sizes, dominator paths, class counts, and allocation trends. A large object is not automatically a leak; the useful question is why it remains reachable. For native or direct memory, heap dumps may look normal, so inspect native memory tracking, thread count, buffer ownership, and operating-system evidence.

Bound Retention and Allocation Before Raising Limits

A larger heap can provide necessary capacity, but it can also postpone a leak and lengthen recovery. Bound caches by size and lifetime, stream large inputs, page database results, release direct buffers through their owning API, and remove listeners or ThreadLocal values when their scope ends. Avoid collecting an unbounded result before writing the first byte of output.

Reproduce the failure with a representative load and keep the diagnostic artifacts from the failing run. After a correction, compare live-set size after full collection, allocation rate, pause behavior, throughput, and container headroom. The test should run long enough to distinguish a stable plateau from slow retention growth.

Before you move on

OutOfMemoryError in Java: Causes and Fixes Mastery Check

4 checks
  • I can use the exact OutOfMemoryError message to identify the exhausted memory area.
  • I can capture a heap dump and GC evidence before restarting removes the useful state.
  • I can distinguish a retained-object leak from a workload that needs bounded or streamed processing.
  • I can validate a code or heap-size correction under a representative load instead of guessing at -Xmx.

Try this next

Core Java Out Of Memory Error Repair Drills

0 of 2 completed

  1. Reproduce growth in a static map, inspect a heap dump for the retaining path, then add a size or lifetime policy and verify live memory stabilizes. Increasing -Xmx delays an unbounded-retention defect but does not remove it.
  2. Replace a read-all CSV import with batched processing and record peak heap usage for both versions on the same generated data set. Keep only the current batch and durable aggregates reachable.

Core Java Questions Learners Ask

"Java heap space" means the heap is full. "GC overhead limit exceeded" means GC is running constantly (>98% of time) but recovering less than 2% of heap "" effectively the heap is full but GC keeps trying.

Use JVM flags: -Xms for initial heap, -Xmx for maximum heap. Example: java -Xms256m -Xmx2g MyApp. For servers, set both to the same value to avoid heap resizing overhead.

Use profiling tools like VisualVM (free), JProfiler, or YourKit. Take heap dumps with jmap and analyze with Eclipse MAT. Look for objects that keep growing in count over time.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.