By the normal definition of a memory leak, Java does not have them due to Garbage collection. If we, however, expand the definition a little bit to "Objects the program does not need anymore, but are not garbage-collectible", then there are two scenarios I can think of where such "leaks" could arise.
Scenario 1: record all objects of a class ever created
This example has an artificial taste and is often seen in the context of an exercise. Suppose we want to store every instance of a certain class ever created. This can be achived through a static colleciton:
public class RecordMe {
private static final List<RecordMe> created = new ArrayList<RecordMe>();
...
private final int someValue;
private RecordMe(final int someValue) {
this.someValue = someValue;
}
public static RecordMe of(final int someValue) {
RecordMe me = new RecordMe(someValue);
created.add(me);
return me;
}
public static List<RecordMe> instances() {
return Collections.unmodifiableList(created);
}
}
As soon as an instance of RecordMe
is created, it can never be garbage-collected because it will always be referenced through the static list.
The fix would be to check the list before creating a new instance of RecordMe
or use List<
WeakReference<RecordMe>
>
(and clean this list from time to time).
Scenario 2: Leaks through inner classes
As we know, a non-staitc inner class holds an implicit reference to the object it was created from. Let's take a look on an extreme example.
public class MemoryTest {
// data has a size of a little over 512 MB.
private final byte[] data = new byte[1024 * 1024 * 512];
private final Field field;
public class Field {
}
public MemoryTest() {
this.field = new Field();
}
public Field getField() {
return this.field;
}
public static void main(String... args) {
MemoryTest test = new MemoryTest();
Field fieldOne = test.getField();
test = null;
test = new MemoryTest();
}
}
If we execute this code with java -Xmx800m MemoryTest
, it will throw an OutOfMemoryException
. Examples of this sizes are unrealistic in the real, but in smaller sizes and with enough instances, this can also lead to issues. Take, for example, Java's HashMap
-implementation. Method keySet()
returns an instance of a non-static, inner class. As long as one holds instances to those inner classes, the HashMap
cannot be garbage-collected.