The most recent Java Specialists Newsletter finally convinced me to start this post that I was having in mind for quite some time.
One of the really huge advantages of Java is that you almost do not have to care about cleaning up your memory as the Garbage Collector usually does this for you as soon as Objects are no more referenced. Usually this works really really well so that you really don’t have to care about annything! But maybe once in a while you may be observing something like a memory leak. Some people then call the Garbage explicitly – which is usually just a bad idea and possibly also doesn’t help either so that the “leak” remains. The better solution in this case would be profiling so that you can see why some classes are not cleaned up.
A nice source for memory leaks can be the use of anonymous inner classes. Assume the following class where you want to compute s.th and return a Result-Object which derives from an Interface:
interface Result{} class Outer { int[] data = null; public Outer(int s) { data = new int[s]; } Object getResult() { return new Result(){}; } }
So if you call new Outer(1).getResult()
, you will still have an instance of Outer
in memory even though you did not keep an explicit reference. As explained in the Java Specialists Newsletter, each instance of an anoymous inner class always keeps a reference to the outer class! This is not a big deal as long as
- you don’t keep a lot of data in the
Outer
instance or - if the lifetime of the Result object is not long or
- if you won’t create a lot of results anyways.
Let’s have an example. If you execute
ArrayList l = new ArrayList(); int i = 0; while(true){ l.add(new Outer(0).getResult()); System.out.println(i++); }
with the above classes without memory constraints (-Xmx), this will run for quite some time because you are only holding 2 class references (Outer
, Result
) 1 field (the emtpty data array) and an implicit reference from Result
to Outer
. Which makes a total of 48 bytes on my Win7 64bit machine (according to this measurement).
Now change the parameter in the constructor of Outer
from 0 to 100000 and execute the code again. In my case I am getting an OutOfMemoryException after a bit more than 2000 created instances as now suddenly each iteration consumes 400.048 bytes (48 bytes as before + 100.000*4 bytes for the int-array) even though we only keep the explicit reference to the Result objects!
So – if you are creating an inner class the next time – you might have a brief look at the outer class as well and think about memory consumption and lifetime.