SoFunction
Updated on 2025-04-05

How to solve memory overflow and memory leak in Java

Memory overflow

Memory overflow (OutOfMemoryError) refers to the program trying to allocate memory at runtime, but because there is not enough memory available, the Java virtual machine (JVM) throws it.OutOfMemoryErrormistake. Common memory overflow areas include heap memory and permanent generation (replaced by metaspace after Java 8).

Causes

There are several main reasons for memory overflow: 1. 2.Heap memory overflow: Creates a large number of objects, causing the heap memory to run out. 2.Stack memory overflow: The recursive call is too deep, causing the stack memory to run out. 3.Permanent generation/metaspace overflow: Too much class loading, resulting in permanent generation/metaspace exhaustion.

Below we use three examples to show the heap memory overflow, stack memory overflow and permanent generation/metaspace overflow:

Heap memory overflow

The following sample code is continuously used toArrayListAdd objects to exhaust heap memory.

import ;
import ;

public class HeapMemoryOverflow {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        while (true) {
            (new Object());
        }
    }
}

Running the aboveHeapMemoryOverflowWhen examples, it may be necessary to adjust the JVM parameters to run at a smaller heap size, e.g.-Xmx10m, to observe fasterOutOfMemoryError

Stack memory overflow

The following example code causes the stack memory to overflow by recursively calling a method without a termination condition.

public class StackMemoryOverflow {
    public static void main(String[] args) {
        recursiveMethod();
    }

    public static void recursiveMethod() {
        // Recursive call without termination condition        recursiveMethod();
    }
}

run*ErrorCode usually causes stack memory overflow very quickly because the default stack size is not large.

Permanent generation/metaspace overflow

Before Java 8, permanent generation overflow could be simulated by dynamically generating a large number of classes. After Java 8, permanent generation was replaced by metaspace. The following is an example of dynamically generating classes using CGLIB, which may cause metaspace overflow and requires the addition of CGLIB library dependencies.

import ;
import ;
import ;

import ;

public class MetaspaceOverflow {
    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            ();
            (false);
            (new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    return (obj, args);
                }
            });
            ();
        }
    }

    static class DummyClass {
    }
}

RunMetaspaceOverflowWhen using the example, you can use JVM parameters-XX:MaxMetaspaceSize=10mto limit the size of the element space to observe overflow faster.

Solution

Here, we just gave a big idea, and the investigation of memory overflow is also a very important knowledge point, which we will introduce in detail in the following article.

  • Increase memory: Adjust JVM parameters to increase the heap memory size, such as-Xmx

  • Optimize code: Reduce unnecessary object creation and optimize data structure.

  • Check for recursion: Avoid too deep recursive calls.

  • Monitoring and analysis: Use tools such as JVisualVM and JProfiler to analyze memory usage.

Memory leak

Memory Leak refers to the existence of some objects in the program that are no longer used, but because they are still referenced, the garbage collector cannot recycle these objects. Therefore, over time, memory leaks can cause a gradual decrease in available memory, which can eventually lead to memory overflow.

Causes

There are several main reasons for memory leakage:

  • Static collection class:usestaticThe modified collection class holds object references. Because the life cycle of the static collection is consistent with the JVM, the objects referenced by the static collection cannot be released.

  • Listeners and callbacks: The registered listener or callback has not been removed.

  • Long life cycle objects hold short life cycle objects: Long-life cycle objects do not hold references to short-life cycle objects.

Below we use three examples to show the possible scenarios of memory leaks:

Memory leak caused by static collection classes

Static collection classes hold object references, which make these objects unable to be garbage collected.

import ;
import ;

public class StaticCollectionLeak {
    // Static collection holds object reference    private static List&lt;Object&gt; objectList = new ArrayList&lt;&gt;();

    public static void main(String[] args) {
        for (int i = 0; i &lt; 10000; i++) {
            // Create a new object at a time and add it to the static collection            (new Object());
        }
        // Even here trying to clean up some other references        ();  // These objects are still not recyclable because they are referenced by static collections    }
}

Listeners and callbacks have not been removed

The registered listener or callback has not been removed, resulting in a memory leak.

import ;
import ;

public class ListenerLeak {
    private List&lt;EventListener&gt; listeners = new ArrayList&lt;&gt;();

    public void addListener(EventListener listener) {
        (listener);
    }

    public void triggerEvent() {
        for (EventListener listener : listeners) {
            ();
        }
    }

    public static void main(String[] args) {
        ListenerLeak leakExample = new ListenerLeak();
        
        // Listener object created by anonymous class        (new EventListener() {
            @Override
            public void onEvent() {
                ("Event triggered");
            }
        });

        // Assume that at some point the listener is no longer needed, but not removed        // (listener); // Unwanted listeners should be removed    }
}

interface EventListener {
    void onEvent();
}

Long life cycle objects hold short life cycle objects

Long-life cycle objects improperly hold references to short-life cycle objects, resulting in short-life cycle objects being unable to be recycled.

import ;
import ;

public class LongLifeCycleLeak {
    private static Map&lt;String, byte[]&gt; cache = new HashMap&lt;&gt;();

    public static void main(String[] args) {
        while (true) {
            // Short life cycle object            byte[] data = new byte[1024 * 1024]; // 1MB

            // Long life cycle object holds references to short life cycle objects            ((()), data);

            // You need to remove data that is no longer needed regularly, otherwise it will cause memory leaks            // (); // The cache should be cleaned at the appropriate time        }
    }
}

Solution

Here, we just gave a big idea, and the investigation of memory leaks is also a very important knowledge point, which we will introduce in detail in the following article.

  • Release citations in time: Ensure that object references that are no longer used are cleared.

  • Use weak references: Used on cached or non-critical objectsWeakReference. For example, weak references to ThreadLocal will cause memory leakage, so after using ThreadLocal, you must remember to use the remove method to clear it.

  • Properly manage life cycles: Especially listeners and callbacks, make sure to be removed when not needed.

Sample code

The following sample code is used to test for memory leaks.

import ;
import ;

public class MemoryLeakExample {
    private static Map<Integer, String> map = new HashMap<>();

    public static void main(String[] args) {
        for (int i = 0; i < 100000; i++) {
            (i, "value" + i);
        }
    }
}

In the above code, ifmapIt is a long-standing static variable and is not cleaned up in time, which may lead to memory leakage.

contrast

The comparison of memory overflow and memory leak is as follows:

  • Trigger timing: Memory overflow is usually triggered immediately when memory runs out, while memory leaks may gradually appear after a period of time.

  • Range of impact: Memory overflows immediately affect the availability of the program, and memory leaks are usually a gradual accumulation issue.

  • Detection difficulty: Memory overflow is easier to detect, while memory leaks often require in-depth analysis and debugging.

  • Solve complexity: The solution to memory overflow is relatively simple, usually by optimizing memory usage or increasing memory. While the solution to memory leaks requires identification and cleaning of unnecessary references, it may involve more complex code refactoring.

This is the end of this article about how to solve memory overflow and memory leaks in Java. For more related Java memory overflow and memory leaks, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!