Java Memory Leaks w/ Finalize Examples
Most people think Java cannot leak memory, but actually that’s not true. Java, unlike languages such as C or Javascript, can have two kinds of memory leaks:
- True leaks - unreferenced, unrecoverable segments of memory
- Soft leaks - memory that could be garbage collected, but is “accidentally” referenced
The first kind of memory leak, the true leak, is common to C. It’s trivially easy to write a C program which leaks memory like a sieve by simple putting a call to malloc(…) inside a tight loop. This creates unbounded amounts of heap memory and eventually runs out of space. Additionally, the memory is lost if you don’t save a pointer to it. However, the same program in Java will not run out of memory:
public class finalizer {
public static void main(String[] args) {
while (true) {
finalizer f = new finalizer();
System.out.println("" + Runtime.getRuntime().freeMemory() + " bytes free!");
}
}
}
The output looks similar to this:
15757280 bytes free!
15965176 bytes free!
16274928 bytes free!
16584368 bytes free!
15770768 bytes free!
…
As you can see, since the object we create are unreferenced, the garbage collector can clean them up. Circular references are also no problem for the Java garbage collector, which uses a generational mark-and-sweep algorithm, as demonstrated by this example:
import java.util.LinkedList;
import java.util.List;
public class finalizer {
protected Object ref;
public finalizer(Object ref){
this.ref = ref;
}
public static void main(String[] args) {
while (true) {
List x = new LinkedList();
for (int i = 0; i < 100000; i++) {
x.add(new finalizer(x));
}
x = null;
System.out.println("" + Runtime.getRuntime().freeMemory() + " bytes free!");
}
}
}
This creates a linked list in which every element also contains a reference to the list, then blows away the scope of the list entirely by dereferencing x and moving into a new loop scope. This leaves all the elements we just allocated floating in memory and all pointing at each other, but not pointed to by our active memory graph. The output shows that this memory is reclaimed:
12601488 bytes free!
8597784 bytes free!
4584656 bytes free!
12596808 bytes free!
…
Unfortunately, though, there is a way to create true memory leaks in java, and that is with a poor implementation of the finalize method, which is described in the Java 6 docs as:
The general contract of finalize is that it is invoked if and when the JavaTM virtual machine has determined that there is no longer any means by which this object can be accessed by any thread that has not yet died, except as a result of an action taken by the finalization of some other object or class which is ready to be finalized.
The finalize method exists on every Object and is called by the garbage collector’s thread before it reclaims that memory. So, the simplest thing we can do to prevent the garbage collector from reclaiming it is to yield execution:
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!");
}
}
}
This produces a quick memory leak and Out of Memory Exception:
12591736 bytes free!
8599816 bytes free!
4584576 bytes free!
602496 bytes free!
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
Throwing any kind of Exception or Error from finalize() also prevents the garbage collector from reclaiming the memory:
public class finalizer {
@Override
protected void finalize() throws Throwable {
throw new Exception("x");
}
public static void main(String[] args) {
while (true) {
for (int i = 0; i < 100000; i++)
new finalizer();
System.out.println("" + Runtime.getRuntime().freeMemory()
+ " bytes free!");
}
}
}
12380920 bytes free!
8687296 bytes free!
5608880 bytes free!
1796496 bytes free!
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
Abuse of the Object.finalize(…) contract is the only way I know of in pure Java to create a true memory leak. If you widen the scope to include JNI (Java Native Interface), you can bind to an object which leaks memory in native code, but inside the process space of your Java application.
java.lang.OutOfMemoryError
Isn’t this a cute little error:
Exception java.lang.OutOfMemoryError: requested 4096000 bytes for GrET* in C:/BUILD_AREA/jdk1.5.0_09/hotspot\src\share\vm\utilities\growableArray.cpp. Out of swap space?
I got home from Shanghai to see this guy, although I’m not sure why a request for 4MB of memory would fail…
Update: I wasn’t leaking memory or anything, either. And I gave a big heap to play with. Maybe the system as a whole ran out of some kind of addressable memory, say threads or process space, and it threw this error. I don’t honestly know, since this was on Windows XP 32bit Pro, and not linux. I neglected at the time to save a coredump, as well.
Name clash: The method BLAH has the same erasure as type BLAH but does not override it
I was getting the following error in Eclipse IDE 3.1 and Java 1.5 (or 5.0 as some like to call it):
Name clash: The method removeEldestEntry(Map.Entry<K ,V>) of type LRUMap<K ,V> has the
same erasure as removeEldestEntry(Map.Entry<K , V>) of type LinkedHashMap<K , V> but does not
override it
The class in question looked like this:
class LRUMap <K , V> extends LinkedHashMap {
public LRUMap(){
super(10000, .75f, true);
}
protected boolean removeEldestEntry (Entry <K , V> eldest) {
return this.size() > 262144;
}
}
The problem is that I was extending LinkedHashMap without type parameters, not LinkedHashMap >K ,V<. Changing the code to:
class LRUMap <K , V> extends LinkedHashMap <K , V> {
public LRUMap(){
super(10000, .75f, true);
}
protected boolean removeEldestEntry (Entry <K , V> eldest) {
return this.size() > 262144;
}
}
completely fixed the problem! Type erasure is sure a pain, no? I should probably spend more time at home reading the Java Generics Tutorial.
Programming Truth and Fiction Revisited
Well-esteemed Philipp Lenssen gives in Programming Truth and Fiction a set of false programming stereotypes and misconceptions, and then sets out to correct them. However, he is not correct in all cases. I take issue with the following in particular:
A complicated class structure only shows the programmer did a quality job. Inheritance is a necessary complexity, and simply can’t be overused.
Besides that quality code can be written without the aid of OOP, see Wordpress as an example of so-called “bad” code, or many web scripting solutions, I believe inheritence can actually be terribly overused. For example, if you model every possible permutation of a thing into a class structure as the “sum of its parts:”

Yes, you can define a car as the sum of a Red Toyota 8 Cylinder Engine. And you can say, hmm, all sorts of engines are an engine, and recursively apply this principle to all the parts of the car, leading to what? A huge mess. OOP can be taken to a frightful and useless extreme.
There’s a huge difference between scripting languages and programming languages.
First, ignoring that a scripting language is intended for a completely different purpose than a programing language, I have to point out that as long as both languages are Turing complete, they are reducible to one another, and therefore there’s technically no difference between them.
Programming is for nerds! If you want to teach it, wait until 9th grade and use Java. Seriously.
No. Start at 2 and put an SML interpreter on the locks of their bedroom doors and leave them datastructure puzzles.
PANIC MODE JAVA
I’ve decided that Sun Micrososystems has screwed up with Java. See, they have a great API, but every now and then you find some kind of inconsistency that really makes you wonder “WHY.” For example, things in real life which can be compared to each other generally ought to implement the Comparable interface in Java so that you can compare them as objects. However, java . net . URL doesn’t implement Comparable, and therefore I am forced to conclude that a Uniform Resource Locator is fundamentally un-comparable. Except that it’s not. Every search engine has figured out how to handle URLs, but for some reason Java hasn’t.
Let me give you a hint–it’s not too hard. Just compare the protocol, the domain, and the paths. Then compare the query string. Of course there can be aliasing of all kinds on the server side, but couldn’t you lazy programmers at least have tried something?
