Rectangle 27 0

Creating a memory leak with Java?


MemLeak.class.getClassLoader().getResourceAsStream("resource.txt").close();
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class BigJarCreator {
    public static void main(String[] args) throws IOException {
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File("big.jar")));
        zos.putNextEntry(new ZipEntry("resource.txt"));
        zos.write("not too much in here".getBytes());
        zos.closeEntry();
        zos.putNextEntry(new ZipEntry("largeFile.out"));
        for (int i=0 ; i<10000000 ; i++) {
            zos.write((int) (Math.round(Math.random()*100)+20));
        }
        zos.closeEntry();
        zos.close();
    }
}
javac BigJarCreator.java
java -cp . BigJarCreator
javac MemLeak.java
java -Xmx2m -classpath .:big.jar MemLeak
public class MemLeak {
    public static void main(String[] args) throws InterruptedException {
        int ITERATIONS=100000;
        for (int i=0 ; i<ITERATIONS ; i++) {
            MemLeak.class.getClassLoader().getResourceAsStream("resource.txt");
        }
        System.out.println("finished creation of streams, now waiting to be killed");

        Thread.sleep(Long.MAX_VALUE);
    }

}

All you need is a jar file with a file inside which will be referenced from Java code. The bigger the jar file, the quicker memory gets allocated.

Et voil: you find a jar archive in your current working directory with two files inside.

I came across a more subtle kind of resource leak recently. We open resources via class loader's getResourceAsStream and it happened that the input stream handles were not closed.

If you want the application to play safe, close the input stream right where it's created:

If you're doubtful, try to compile and start the class above, but make sure to chose a decent heap size (2 MB):

Just paste into a file named BigJarCreator.java, compile and run it from command line:

Let's create a second class:

This class basically does nothing, but create unreferenced InputStream objects. Those objects will be garbage collected immediately and thus, do not contribute to heap size. It is important for our example to load an existing resource from a jar file, and size does matter here!

Uhm, you might say, what an idiot.

Well, what makes this interesting is: this way, you can leak heap memory of the underlying process, rather than from JVM's heap.

You can easily create such a jar with the following class:

You will not encounter an OOM error here, as no references are kept, the application will keep running no matter how large you chose ITERATIONS in the above example. The memory consumption of your process (visible in top (RES/RSS) or process explorer) grows unless the application gets to the wait command. In the setup above, it will allocate around 150 MB in memory.

and your process will not exceed 35 MB, independent of the iteration count.

Note
Rectangle 27 0

Creating a memory leak with Java?


public class Example1 {
  public Example2 getNewExample2() {
    return this.new Example2();
  }
  public class Example2 {
    public Example2() {}
  }
}
public class Referencer {
  public static Example2 GetAnExample2() {
    Example1 ex = new Example1();
    return ex.getNewExample2();
  }

  public static void main(String[] args) {
    Example2 ex = Referencer.GetAnExample2();
    // As long as ex is reachable; Example1 will always remain in memory.
  }
}

I thought it was interesting that no one used the internal class examples. If you have an internal class; it inherently maintains a reference to the containing class. Of course it is not technically a memory leak because Java WILL eventually clean it up; but this can cause classes to hang around longer than anticipated.

I've also heard a rumor that if you have a variable that exists for longer than a specific amount of time; Java assumes that it will always exist and will actually never try to clean it up if cannot be reached in code anymore. But that is completely unverified.

Now if you call Example1 and get an Example2 discarding Example1, you will inherently still have a link to an Example1 object.

inner classes are rarely an issue. They are a straightforward case and very easy to detect. The rumor is just a rumor too.

Note
Rectangle 27 0

Creating a memory leak with Java?


MemLeak.class.getClassLoader().getResourceAsStream("resource.txt").close();
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class BigJarCreator {
    public static void main(String[] args) throws IOException {
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File("big.jar")));
        zos.putNextEntry(new ZipEntry("resource.txt"));
        zos.write("not too much in here".getBytes());
        zos.closeEntry();
        zos.putNextEntry(new ZipEntry("largeFile.out"));
        for (int i=0 ; i<10000000 ; i++) {
            zos.write((int) (Math.round(Math.random()*100)+20));
        }
        zos.closeEntry();
        zos.close();
    }
}
javac BigJarCreator.java
java -cp . BigJarCreator
javac MemLeak.java
java -Xmx2m -classpath .:big.jar MemLeak
public class MemLeak {
    public static void main(String[] args) throws InterruptedException {
        int ITERATIONS=100000;
        for (int i=0 ; i<ITERATIONS ; i++) {
            MemLeak.class.getClassLoader().getResourceAsStream("resource.txt");
        }
        System.out.println("finished creation of streams, now waiting to be killed");

        Thread.sleep(Long.MAX_VALUE);
    }

}

All you need is a jar file with a file inside which will be referenced from Java code. The bigger the jar file, the quicker memory gets allocated.

Et voil: you find a jar archive in your current working directory with two files inside.

I came across a more subtle kind of resource leak recently. We open resources via class loader's getResourceAsStream and it happened that the input stream handles were not closed.

If you want the application to play safe, close the input stream right where it's created:

If you're doubtful, try to compile and start the class above, but make sure to chose a decent heap size (2 MB):

Just paste into a file named BigJarCreator.java, compile and run it from command line:

Let's create a second class:

This class basically does nothing, but create unreferenced InputStream objects. Those objects will be garbage collected immediately and thus, do not contribute to heap size. It is important for our example to load an existing resource from a jar file, and size does matter here!

Uhm, you might say, what an idiot.

Well, what makes this interesting is: this way, you can leak heap memory of the underlying process, rather than from JVM's heap.

You can easily create such a jar with the following class:

You will not encounter an OOM error here, as no references are kept, the application will keep running no matter how large you chose ITERATIONS in the above example. The memory consumption of your process (visible in top (RES/RSS) or process explorer) grows unless the application gets to the wait command. In the setup above, it will allocate around 150 MB in memory.

and your process will not exceed 35 MB, independent of the iteration count.

Note
Rectangle 27 0

Creating a memory leak with Java?


public class Example1 {
  public Example2 getNewExample2() {
    return this.new Example2();
  }
  public class Example2 {
    public Example2() {}
  }
}
public class Referencer {
  public static Example2 GetAnExample2() {
    Example1 ex = new Example1();
    return ex.getNewExample2();
  }

  public static void main(String[] args) {
    Example2 ex = Referencer.GetAnExample2();
    // As long as ex is reachable; Example1 will always remain in memory.
  }
}

I thought it was interesting that no one used the internal class examples. If you have an internal class; it inherently maintains a reference to the containing class. Of course it is not technically a memory leak because Java WILL eventually clean it up; but this can cause classes to hang around longer than anticipated.

I've also heard a rumor that if you have a variable that exists for longer than a specific amount of time; Java assumes that it will always exist and will actually never try to clean it up if cannot be reached in code anymore. But that is completely unverified.

Now if you call Example1 and get an Example2 discarding Example1, you will inherently still have a link to an Example1 object.

inner classes are rarely an issue. They are a straightforward case and very easy to detect. The rumor is just a rumor too.

Note
Rectangle 27 0

Creating a memory leak with Java?


  • The application creates a long-running thread (or use a thread pool to leak even faster).
  • The class allocates a large chunk of memory (e.g. new byte[1000000]), stores a strong reference to it in a static field, and then stores a reference to itself in a ThreadLocal. Allocating the extra memory is optional (leaking the Class instance is enough), but it will make the leak work that much faster.
  • The thread clears all references to the custom class or the ClassLoader it was loaded from.
  • The thread loads a class via an (optionally custom) ClassLoader.

+1 ClassLoader leaks are some of the most commonly painful memory leaks in the JEE world, often caused by 3rd party libs that transform data (BeanUtils, XML/JSON codecs). This can happen when the lib is loaded outside your application's root classloader but holds references to your classes (eg. by caching). When you undeploy/redeploy your app the JVM is unable to garbage collect the app's classloader (and therefore all classes loaded by it), so with repeat deploys the app server eventually borks. If lucky you get a clue with ClassCastException z.x.y.Abc cannot be cast to z.x.y.Abc

+1: Classloader leaks are a nightmare. I spent weeks trying to figure them out. The sad thing is, as what @earcam has said, they are mostly caused by 3rd party libs and also most profilers can't detect these leaks. There's a good and clear explanation on this blog about Classloader leaks. blogs.oracle.com/fkieviet/entry/

@Nicolas: Are you sure? JRockit does GC Class objects by default, and HotSpot doesn't, but AFAIK JRockit still can't GC a Class or ClassLoader that is referenced by a ThreadLocal.

A variation on this pattern is why application containers (like Tomcat) can leak memory like a sieve if you frequently redeploy applications that happen to use ThreadLocals in any way. (Since the application container uses Threads as described, and each time you redeploy the application a new ClassLoader is used.)

Here's a good way to create a true memory leak (objects inaccessible by running code but still stored in memory) in pure Java:

This works because the ThreadLocal keeps a reference to the object, which keeps a reference to its Class, which in turn keeps a reference to its ClassLoader. The ClassLoader, in turn, keeps a reference to all the Classes it has loaded. It gets worse because in many JVM implementations Classes and ClassLoaders are allocated straight into permgen and are never GC'd at all.

Tomcat will try to detect these leaks for you, and warn about them: wiki.apache.org/tomcat/MemoryLeakProtection. The most recent version will sometimes even fix the leak for you.

tomcat uses tricks and nils ALL static variables in ALL loaded classes, tomcat has a lot of dataraces and bad coding though (need to get some time and submit fixes), plus the all mind-boggling ConcurrentLinkedQueue as cache for internal (small) objects, so small that even the ConcurrentLinkedQueue.Node takes more memory.

Note
Rectangle 27 0

Creating a memory leak with Java?


...
this.muchSmallerString = new String(veryLongString.substring(0, 1));
...
...
this.muchSmallerString = veryLongString.substring(0, 1).intern();
...
.intern()
public class StringLeaker
{
    private final String muchSmallerString;

    public StringLeaker()
    {
        // Imagine the whole Declaration of Independence here
        String veryLongString = "We hold these truths to be self-evident...";

        // The substring here maintains a reference to the internal char[]
        // representation of the original string.
        this.muchSmallerString = veryLongString.substring(0, 1);
    }
}

@rds, that's a fair point. The non-intern case may be more of a "memory surprise" than a "memory leak." .intern()ing the substring, though, certainly creates a situation where the reference to the longer string is preserved and cannot be freed.

Because the substring refers to the internal representation of the original, much longer string, the original stays in memory. Thus, as long as you have a StringLeaker in play, you have the whole original string in memory, too, even though you might think you're just holding on to a single-character string.

Doing so will keep both the original long string and the derived substring in memory even after the StringLeaker instance has been discarded.

I wouldn't call that a memory leak, per se. When muchSmallerString is freeed (because the StringLeaker object is destroyed), the long string will be freed as well. What I call memory leak is memory that can never been freeed in this instance of JVM. However, you have shown yourself how to free the memory: this.muchSmallerString=new String(this.muchSmallerString). With a real memory leak, there is nothing you can do.

The method substring() creates a new String in java7 (it is a new behavior)

The way to avoid storing an unwanted reference to the original string is to do something like this:

Note
Rectangle 27 0

Creating a memory leak with Java?


File.deleteOnExit()
char[]

@bestsss: THANK YOU! Months ago I asked a question based on the premises that Java had (subtle or not) memory leak and I got assaulted and got my honesty questionned. Now this question is referenced from my other question: stackoverflow.com/questions/4400311

Below there will be non-obvious case where java leaks, besides the standard case of forgotten listeners, static references, bogus/modifiable keys in hashmaps, or just threads stuck w/o any chance to end their life-cycle.

Creating but not starting a Thread... Yikes, I was badly bitten by this one some centuries ago! (Java 1.3)

Good luck and stay safe, leaks are evil!

I'll concentrate on Threads to show the danger of unmanaged threads mostly, don't wish to even touch swing.

Note
Rectangle 27 0

Creating a memory leak with Java?


private static final Map<String, Info> myCache = new HashMap<>();

public void getInfo(String key)
{
    // uses cache
    Info info = myCache.get(key);
    if (info != null) return info;

    // if it's not in cache, then fetch it from the database
    info = Database.fetch(key);
    if (info == null) return null;

    // and store it in the cache
    myCache.put(key, info);
    return info;
}

The garbage collector cannot clean it.

  • It's a waste of memory.

A cache of objects is a good starting point to mess things up.

If this Info object has references to other objects, which again have references to other objects. In a way you could also consider this to be some kind of memory leak, (caused by bad design).

What's a memory leak:

Your cache grows and grows. And pretty soon the entire database gets sucked into memory. A better design uses an LRUMap (Only keeps recently used objects in cache).

Note
Rectangle 27 0

Creating a memory leak with Java?


A common example of this in GUI code is when creating a widget/component and adding a listener to some static/application scoped object and then not removing the listener when the widget is destroyed. Not only do you get a memory leak but a performance hit as when whatever you are listening too fires events all your old listeners are called too.

Note
Rectangle 27 0

Creating a memory leak with Java?


String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you cant remove
str.intern();
String.intern()
class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}
getServletContext().setAttribute("SOME_MAP", map);
session.setAttribute("SOME_MAP", map);
try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}
try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

Areas that are unreachable from JVM's garbage collector

In web applications objects stored in application scope till application is restarted or removed explicitly

(Unclosed) open streams ( file , network etc... ), doesn't leak for real, during finalization (which will be after the next GC cycle) close() is going to be scheduled (close() is usually not invoked in the finalizer thread since might be a blocking operation). It's a bad practice not to close, but it doesn't cause a leak. Unclosed java.sql.Connection is the same.

How Static field holding object reference [esp final field] is a memory leak ??

I'd disagree that context and session attributes are "leaks." They're just long-lived variables. And the static final field is more or less just a constant. Maybe large constants should be avoided, but I don't think it's fair to call it a memory leak.

In most sane JVMs, it appears as though the String class only has a weak reference on its intern hashtable contents. As such, it is garbage collected properly and not a leak. (but IANAJP) mindprod.com/jgloss/interned.html#GC

Reference loops used to be leaks as well. That is where you have instance A referencing instance B, which references instance C, which references instance A, but nothing else references any of those. (The loop may need to be bigger)

like noclassgc option on IBM JDK that prevents unused class garbage collection

Note