How to simulate java.lang.OutOfMemoryError in Java

In this article, we demonstrate various methods to simulate a java.lang.OutOfMemoryError. We use practical examples so that we can better understand how our applications might run out of memory when objects are continuously allocated. These examples help us to test our error handling and tuning of Java heap space in real-world scenarios.

Table of contents

Example 1: Using an ArrayList to Consume Heap Memory

In our first example, we simulate an OutOfMemoryError by creating 1MB objects (byte arrays) in an infinite loop and adding them to an ArrayList. Each loop iteration allocates a new byte array of 1MB, and since we never remove these objects, the JVM eventually runs out of heap memory.

JavaEatMemory.java

package com.mkyong;

import java.util.ArrayList;
import java.util.List;

public class JavaEatMemory {

    public static void main(String[] args) {
        List<byte[]> list = new ArrayList<>();
        int index = 1;
        while (true) {
            // Allocate 1MB each loop (1 x 1024 x 1024 = 1048576 bytes)
            byte[] b = new byte[1048576];
            list.add(b);
            // Get the current free memory
            Runtime rt = Runtime.getRuntime();
            System.out.printf("[%d] free memory: %s%n", index++, rt.freeMemory());
        }
    }
}

Output:


[14299] free memory: 2134669728
[14300] free memory: 2133621136
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.mkyong.wpbackend.TestJava.main(JavaEatMemory.java:13)

In this example, we actively monitor the free memory and observe how it decreases until the JVM throws an OutOfMemoryError.

Example 2: Simulating Memory Leak with a HashMap

In this second example, we simulate a memory leak using a HashMap. Here, we continuously add entries to the map without ever removing any of them. This approach is similar to the first example but uses a different data structure, which can be useful when we want to see how different collections impact memory consumption.

MemoryLeakSimulator.java

package com.mkyong;

import java.util.HashMap;
import java.util.Map;

public class MemoryLeakSimulator {

    public static void main(String[] args) {
        Map<Integer, byte[]> map = new HashMap<>();
        int index = 1;
        while (true) {
            // Allocate 1MB and put it into the HashMap
            byte[] b = new byte[1048576];
            map.put(index, b);
            // Display current free memory
            Runtime rt = Runtime.getRuntime();
            System.out.printf("Entry %d added, free memory: %s%n", index++, rt.freeMemory());
        }
    }
}

Output:


Entry 14295 added, free memory: 2138392136
Entry 14296 added, free memory: 2137343544
Entry 14297 added, free memory: 2136294952
Entry 14298 added, free memory: 2135246360
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.mkyong.wpbackend.TestJava.main(MemoryLeakSimulator.java:13)

In this example, we simulate how a memory leak occurs when a map continuously grows. We actively add new entries and monitor memory usage, just like in the ArrayList example.

Example 3: Continuous String Allocation

Another way to simulate an OutOfMemoryError is by concatenating strings in a loop. Although not as direct as allocating large arrays, string concatenation can eventually fill up the heap if we keep the growing string in memory.

StringMemoryLeak.java

package com.mkyong;

public class StringMemoryLeak {

    public static void main(String[] args) {
        String data = "";
        int index = 1;
        while (true) {
            // Append a constant string to the existing data
            data += "memoryLeak";
            if (index % 1000 == 0) {
                // Print memory information every 1000 iterations
                Runtime rt = Runtime.getRuntime();
                System.out.printf("After %d iterations, free memory: %s%n", index, rt.freeMemory());
            }
            index++;
        }
    }
}

In this example, we keep concatenating strings. The growing string will eventually consume a large portion of the heap, leading the JVM to throw an OutOfMemoryError.

Real-World Implications and Use Cases

When we simulate these scenarios, we can better understand how memory leaks occur and how our applications might behave under heavy memory load. These examples serve as a reminder that:

  • Memory Management: We must always manage our collections and object references wisely.
  • Error Handling: We should implement proper error handling for OutOfMemoryError in critical systems.
  • Performance Tuning: Monitoring and tuning the Java heap is essential for robust application performance.

By testing our applications using these simulation techniques, we can improve performance and ensure our software is robust enough to handle memory-intensive operations.

References

mkyong

Founder of Mkyong.com, passionate Java and open-source technologies. If you enjoy my tutorials, consider making a donation to these charities.

0 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments