41

Possible Duplicate:
Creating a memory leak with Java

What's the easiest way to cause a Java memory leak?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul McKenzie
  • 19,646
  • 25
  • 76
  • 120
  • Are you looking for a contrived example or a very common programming mistake? – mikerobi Feb 09 '11 at 17:50
  • a contrived example would be best please. – Paul McKenzie Feb 09 '11 at 17:51
  • A memory leak is created whenever an object that is not intended to be used has a reference to it. Almost any program one could write would be a contrived example of a memory leak. – OrangeDog Feb 09 '11 at 17:55
  • Take a look at ['Creating a memory leak with java'](http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java) for other ways different than _the easiest_. – Alberto May 31 '12 at 13:26

9 Answers9

35

You cannot really "leak memory" in Java unless you:

  • intern strings
  • generate classes
  • leak memory in the native code called by JNI
  • keep references to things that you do not want in some forgotten or obscure place.

I take it that you are interested in the last case. The common scenarios are:

  • listeners, especially done with inner classes
  • caches.

A nice example would be to:

  • build a Swing GUI that launches a potentially unlimited number of modal windows;
  • have the modal window do something like this during its initialization:
    StaticGuiHelper.getMainApplicationFrame().getOneOfTheButtons().addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e){
    // do nothing...
    }
    })
    

The registered action does nothing, but it will cause the modal window to linger in memory forever, even after closing, causing a leak - since the listeners are never unregistered, and each anonymous inner class object holds a reference (invisible) to its outer object. What's more - any object referenced from the modal windows have a chance of leaking too.

This is why libraries such as EventBus use weak references by default.

Apart from listeners, other typical examples are caches, but I cannot think of a nice example.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
fdreger
  • 12,264
  • 1
  • 36
  • 42
  • 4
    Interned strings are not really memory leaks, they can get garbage-collected, too. The problem is only that they (in the usual implementations) are in a special memory area (PermGen) which is smaller than the rest of the memory, and thus easier fills up. – Paŭlo Ebermann Feb 09 '11 at 18:21
  • You are right. Interned Strings are not a "real" leak (then again, "real leaks" are not possible with jvm). Nevertheless, perm gets collected only when everything else fails and its contents survives major collections, so it's one of the few sources of real memory problems. Also interned strings take space even though they are not referenced from your program. In that sense they are as close to a leak as you can get. – fdreger Feb 09 '11 at 20:04
16

First we have to agree on what a memory leak actually is.

Wikipedia used to describe a memory leak like this:

A memory leak, in computer science (or leakage, in this context), occurs when a computer program consumes memory but is unable to release it back to the operating system.

However this has changed multiple times and right now (02/2023) it says:

In computer science, a memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in a way that memory which is no longer needed is not released.

Depending on the context you need to specify what exactly you are looking for more precisely.

Unreachable dynamically allocated memory

First, let us have a quick look at an example from a language without automatic memory management: In C you can use malloc() in order to allocate some memory. This function returns a pointer to the allocated memory. You must call free() on exactly this pointer in order to release the memory back to the operating system. But what if the pointer is used in multiple places? Who is responsible for calling free()? If you release the memory too early, then some parts of your application that is still working with that memory is broken. If you do not release the memory, you have a leak. If all pointers to the memory allocated are lost (overwritten or lifetime exceeded), then your application will be unable to release the memory back to the operating system. This would fulfill the old definition that Wikipedia had for a memory leak in 2011. To avoid this, you need some kind of contract that defines who is responsible for freeing memory that was allocated. This requires documentation, which must be read, correctly understood and followed by possibly many people creating various opportunities for errors.

Automatic memory management (which Java has) frees you from this danger. In Java you can allocate memory using the keyword new, but there is no free in Java. new returns a "reference", which (in this context) behaves similarly to a pointer. When all references to allocated memory are lost (overwritten or lifetime exceeded) then this is detected automatically and the memory is returned to the operating system.

In Java this type of memory leak is only "available" in case of bugs in the garbage collector, JNI modules that leak memory or similar, but at least in theory you are safe.

Other programming errors

That withstanding it is of course both with and without automatic memory management possible to actively maintain unneeded references. Assume the following class:

class Demo {
    private static final LinkedList<Integer> history = new LinkedList<>(Collections.singleton(0));

    public static int plusPrevious(int value) {
        int result = history.getLast() + value;
        history.add(value);
        return result;
    }
}

Everytime someone calls plusPrevious the history-List grows. But why? Only one value is needed, not the full history. This class is holding on to memory which it does not need. This fulfills the current definition that Wikipedia has for a memory leak.

In this case the error is obvious. However in more complicated scenarios it might not be so easy to decide what is still "needed" and what is not.

At any rate, putting things in static variables is "good" start to get into trouble. If in the example above the history were not static then a user of that class might eventually release the reference to the instance of Demo and thus free the memory. However since it is static the history will hang around until the application as a whole terminates.

yankee
  • 38,872
  • 15
  • 103
  • 162
  • 2
    "But at any time you could still dereference the objects you created and thus freeing the memory". I disagree. The class implementor can hide the object handles from the outside world. – Thomas Eding Jul 07 '11 at 21:45
  • @trinithis: If you have an object that privately wastes memory by allocating huge amounts of memory, then you can't force the object to release the memory without discarding that object as well. But in this case it is still just wasting memory and not a leak. The memory CAN be freed. It will be freed once the object that references the wasted memory is not referenced anymore. Or did I misunderstand you? – yankee Jul 08 '11 at 15:44
  • I think I misunderstood what you meant by 'dereference'. I was thinking the C meaning of the word. – Thomas Eding Jul 09 '11 at 00:17
  • The definition of the term on Wikipedia has changed. It is now this: *"In computer science, a memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in a way that memory which is no longer needed is not released."* This is the definition used by almost all posters, but not this one. – Lii Nov 21 '22 at 07:40
  • 1
    @Lii: I rewrote the whole answer – yankee Feb 05 '23 at 09:56
12

Here's a simple example

public class Finalizer {
    @Override
    protected void finalize() throws Throwable {
        while (true) {
            Thread.yield();
        }
    }

    public static void main(String[] args) {
        while (true) {
            for (int i = 0; i < 100000; i++) {
                Finalizer f = new Finalizer();
            }

            System.out.println("" + Runtime.getRuntime().freeMemory() + " bytes free!");
        }
    }
}
acconrad
  • 3,201
  • 1
  • 22
  • 31
  • 2
    Could you explain a little as to how are you achieving the memory leak in this example? – TheBlueNotebook Jan 21 '15 at 10:13
  • 1
    Not sure but this code seems to work, at least it killed my pc and the processes keeped on the background even after closing eclipse – pescamillam Apr 09 '15 at 20:14
  • 5
    @TheBlueNotebook The finalize method he overrode is what Java normally calls when it is about to free up the memory for an Object. In his main method he creates 100K of finalizers and then tells the JVM to free all memory. The JVM does this politely and calls finalize before actually freeing the memory. The finalize method it calls yields forever, so the objects are never deleted, but the main loop continues, thus creating another 100K Objects that will never be deleted, then another, then another... – Jeutnarg Jan 05 '16 at 18:52
9

Use:

public static List<byte[]> list = new ArrayList<byte[]>();

And then add (big) arrays without removing them. At some point you will run out of memory without suspecting it. (You can do this with any objects, but with big, full arrays you can run out of memory faster.)

In Java, if you dereference an object (it falls out of scope), it is garbage collected. So you have to hold a reference to it in order to have a memory problem.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 1
    This will cause you to run out of memory, but how can you have a leak if you never do anything to break an object reference? – mikerobi Feb 09 '11 at 17:53
  • 7
    @mikerobi - a memory leak is when you "occupy" some memory without cleaning it (and without using it). If you dereference the object, however, it will be garbage collected. – Bozho Feb 09 '11 at 17:55
  • 1
    I understand that, but I don't consider this to be a leak in every case. It is definitely a leak if you mistakenly make a class variable static, it is possibly a leak if you are using it as a global value in a long running process. It is not a leak if your intention is for the data to persist until program termination. The fact that an infinite loop exhausts your memory has nothing to do with the fact that this is a leak. A lot of leaks don't get noticed, unless they continually allocate new data, but having a fixed chunk of orphaned memory is still a leak. – mikerobi Feb 09 '11 at 18:07
  • @mikerobi - I didn't mention a loop ;) I agree that the usage of the static collection determines whether it's a leak or not. But that's how they happen in Java - you cannot have orphaned memory in the sense that you have allocated it, but then forgot about it. This is handled by the garbage collector. – Bozho Feb 09 '11 at 18:10
  • 1
    This is not a memory leak. – Aykut Kllic Sep 03 '13 at 15:57
3
  1. Create a collection of objects at class scope
  2. Periodically add new objects to the collection
  3. Do not drop the reference to the instance of the class that holds the collection

Because there is always a reference to the collection and the instance of the object that owns the collection, the garbage collector will never clean up that memory, thus causing a "leak" over time.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
3

From what I've read in the most voted answer, you are most probably asking for a C-like memory leak. Well, since there's garbage collection, you can't allocate an object, lose all its references and get it still occupying memory - that would be a serious JVM bug.

On the other hand, you can happen to leak threads - which, of course, would cause this state, because you would have some thread running with its references to objects, and you may lose the thread's reference. You can still get the Thread reference through the API - see http://www.exampledepot.com/egs/java.lang/ListThreads.html

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
1

The following extremely contrived Box class will leak memory if used. Objects that are put into this class are eventually (after another call to put to be precise... provided the same object is not re-put into it.) inaccessible to the outside world. They cannot be dereferenced through this class, yet this class ensures they cannot be collected. This is a real leak. I know this is really contrived, but similar cases are possible to do by accident.

import java.util.ArrayList;
import java.util.Collection;
import java.util.Stack;

public class Box <E> {
    private final Collection<Box<?>> createdBoxes = new ArrayList<Box<?>>();
    private final Stack<E> stack = new Stack<E>();

    public Box () {
        createdBoxes.add(this);
    }

    public void put (E e) {
        stack.push(e);
    }

    public E get () {
        if (stack.isEmpty()) {
            return null;
        }
        return stack.peek();
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Thomas Eding
  • 35,312
  • 13
  • 75
  • 106
0

Try this simple class:

public class Memory {
    private Map<String, List<Object>> dontGarbageMe = new HashMap<String, List<Object>>();

    public Memory() {
        dontGarbageMe.put("map", new ArrayList<Object>());
    }

    public void useMemInMB(long size) {
        System.out.println("Before=" + getFreeMemInMB() + " MB");

        long before = getFreeMemInMB();
        while ((before  - getFreeMemInMB()) < size) {
            dontGarbageMe.get("map").add("aaaaaaaaaaaaaaaaaaaaaa");
        }

        dontGarbageMe.put("map", null);

        System.out.println("After=" + getFreeMemInMB() + " MB");
    }

    private long getFreeMemInMB() {
        return Runtime.getRuntime().freeMemory() / (1024 * 1024);
    }

    public static void main(String[] args) {
        Memory m = new Memory();
        m.useMemInMB(15);  // put here apropriate huge value
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lukastymo
  • 26,145
  • 14
  • 53
  • 66
0

It does seem that most of the answers are not C style memory leaks.

I thought I'd add an example of a library class with a bug that will give you an out-of-memory exception. Again, it is not a true memory leak, but it is an example of something running out of memory that you would not expect.

public class Scratch {
    public static void main(String[] args) throws Exception {
        long lastOut = System.currentTimeMillis();
        File file = new File("deleteme.txt");

        ObjectOutputStream out;
        try {
            out = new ObjectOutputStream(
                    new FileOutputStream("deleteme.txt"));

            while (true) {
                out.writeUnshared(new LittleObject());
                if ((System.currentTimeMillis() - lastOut) > 2000) {
                    lastOut = System.currentTimeMillis();
                    System.out.println("Size " + file.length());
                    // out.reset();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class LittleObject implements Serializable {
    int x = 0;
}

You will find the original code and bug description at JDK-4363937: ObjectOutputStream is creating a memory leak

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MrJacqes
  • 373
  • 1
  • 4