The package java.lang.ref contains classes which can wrap any arbitrary object and are used as an indication to the garbage collector that how the underlying object should be garbage collected.
For a Java program, the main advantage of using these classes is to know when an object has been garbage collected. Reference<T>is the abstract base class which has a method get() . This method starts to return null when the underlying object is garbage collected. This only happens at some point after the underlying object is not reachable by the program directly, even though Reference<T> instance is still reachable.
In this example we will analyze the difference between the two subclasses of Reference<T> : SoftReference<T> and WeakReference<T>.
WeakReference: is used to hold an object which will become eligible for the garbage collection as soon as it is not reachable by the program.
SoftReference: lives longer, it will only be garbage collected before an OutOfMemoryError is thrown.
Soft reference vs a normal reference
Let's create an Object which initializes a big array (to create a memory shortage situation). This class also overrides Object#finalize() method. finalize() method is called during a garbage collection cycle when this object has no more references in the rest of the program and is about to be garbage collected.
public class MyObject {
private int[] ints = new int[1000];
private final String name;
public MyObject(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
@Override
protected void finalize() throws Throwable {
System.out.printf("Finalizing: %s%n", name);
}
}
The main class:
public class SoftVsNormal {
public static void main(String[] args) throws InterruptedException {
List<Reference<MyObject>> references = new ArrayList<>();
for (int i = 0; i < 10; i++) {
//create soft reference
MyObject myObject = new MyObject("soft " + i);
Reference<MyObject> ref = new SoftReference<>(myObject);
references.add(ref);
//without wrapping in any reference
new MyObject("normal " + i);
}
//let see which ones' get() will return null
printReferences(references);
}
public static void printReferences(List<Reference<MyObject>> references) {
ExecutorService ex = Executors.newSingleThreadExecutor();
ex.execute(() -> {
try {
//sleep a little in case if finalizers are currently running
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-- printing references --");
references.stream()
.forEach(SoftVsNormal::printReference);
});
ex.shutdown();
}
public static void printReference(Reference<MyObject> r) {
System.out.printf("Reference: %s [%s]%n", r.get(),
r.getClass().getSimpleName());
}
} OutputFinalizing: normal 1 Finalizing: normal 0 Finalizing: normal 9 Finalizing: normal 8 Finalizing: normal 6 Finalizing: normal 5 Finalizing: normal 4 Finalizing: normal 3 Finalizing: normal 2 Finalizing: normal 7 -- printing references -- Reference: soft 0 [SoftReference] Reference: soft 1 [SoftReference] Reference: soft 2 [SoftReference] Reference: soft 3 [SoftReference] Reference: soft 4 [SoftReference] Reference: soft 5 [SoftReference] Reference: soft 6 [SoftReference] Reference: soft 7 [SoftReference] Reference: soft 8 [SoftReference] Reference: soft 9 [SoftReference]
The above output shows that normal objects are garbage collected but all soft references are still reachable till the end.
we ran our main class will limited runtime memory by setting JVM option: -Xmx1m -Xms1m .
In all examples in this tutorials, we will use the same memory settings. The output are taken from Intellij IDE.
Note that above output is different on different runs. If you are not going to have similar outcome in your machine or you see OutOfMemoryError error, you will need to tweak -Xmx and -Xms options.
A quick description what we did above:
The main class creates multiple SofReferences in a loop and let go their underlying references unreachable when the current loop iteration ends.
We are also creating the same object types without wrapping them in the SoftReferences (we are naming these object as 'normal' in the example), this is to compare 'the two', in terms of garbage collection when the program is low in memory.
We are keeping the SoftReferences in a collection so that we can afterward check how many of them will return null on get() call. Keeping an instance of Reference in a collection (or whatever means) does not create a strong reference of the underlying object. If we kept the 'normal' objects straight in a collection, then for sure we would be creating strong references. In all examples, we will purposely be letting MyObject references to go out of reach to see how WeakReference/SoftReference work.
Weak reference vs a normal reference
Let's repeat the same but this time with WeakReferences:
public class WeakVsNormal {
public static void main(String[] args) {
List<Reference<MyObject>> references = new ArrayList<>();
for (int i = 0; i < 10; i++) {
MyObject myObject = new MyObject("weak " + i);
Reference<MyObject> ref = new WeakReference(myObject);
references.add(ref);
new MyObject("normal " + i);
}
SoftVsNormal.printReferences(references);
}
} OutputFinalizing: normal 9 Finalizing: weak 9 Finalizing: weak 2 Finalizing: normal 1 Finalizing: weak 1 Finalizing: normal 0 Finalizing: normal 6 Finalizing: weak 6 Finalizing: normal 5 Finalizing: weak 5 Finalizing: normal 4 Finalizing: normal 3 Finalizing: normal 2 Finalizing: normal 8 Finalizing: weak 8 Finalizing: normal 7 Finalizing: weak 7 -- printing references -- Reference: weak 0 [WeakReference] Reference: null [WeakReference] Reference: null [WeakReference] Reference: weak 3 [WeakReference] Reference: weak 4 [WeakReference] Reference: null [WeakReference] Reference: null [WeakReference] Reference: null [WeakReference] Reference: null [WeakReference] Reference: null [WeakReference]
This time most of the WeakReferences are garbage collected as soon as they become unreachable, just like normal objects.
Soft vs Weak references
public class SoftVsWeak {
public static void main(String[] args) {
List<Reference<MyObject>> references = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Reference<MyObject> ref = new WeakReference<>(
new MyObject("weak " + i));
references.add(ref);
ref = new SoftReference<>(
new MyObject("soft " + i));
references.add(ref);
}
SoftVsNormal.printReferences(references);
}
} OutputFinalizing: weak 2 Finalizing: weak 1 Finalizing: weak 6 Finalizing: weak 5 Finalizing: weak 4 Finalizing: weak 3 Finalizing: weak 7 -- printing references -- Reference: weak 0 [WeakReference] Reference: soft 0 [SoftReference] Reference: null [WeakReference] Reference: soft 1 [SoftReference] Reference: null [WeakReference] Reference: soft 2 [SoftReference] Reference: null [WeakReference] Reference: soft 3 [SoftReference] Reference: null [WeakReference] Reference: soft 4 [SoftReference] Reference: null [WeakReference] Reference: soft 5 [SoftReference] Reference: null [WeakReference] Reference: soft 6 [SoftReference] Reference: null [WeakReference] Reference: soft 7 [SoftReference] Reference: weak 8 [WeakReference] Reference: soft 8 [SoftReference] Reference: weak 9 [WeakReference] Reference: soft 9 [SoftReference]
Some Weak references were garbage collected but soft references were not garbed collected till the end of the execution.
Soft vs Weak vs Normal references
public class SoftVsWeakVsNormal {
public static void main(String[] args) {
List<Reference<MyObject>> references = new ArrayList<>();
for (int i = 0; i < 10; i++) {
//weak
Reference<MyObject> ref = new WeakReference<>(
new MyObject("weak " + i));
references.add(ref);
//soft
ref = new SoftReference<>(
new MyObject("soft " + i));
references.add(ref);
//normal
new MyObject("normal " + i);
}
SoftVsNormal.printReferences(references);
}
} OutputFinalizing: weak 4 Finalizing: normal 2 Finalizing: weak 2 Finalizing: normal 1 Finalizing: normal 0 Finalizing: weak 0 Finalizing: normal 9 Finalizing: weak 9 Finalizing: weak 6 Finalizing: normal 5 Finalizing: weak 5 Finalizing: normal 4 Finalizing: normal 3 Finalizing: normal 8 Finalizing: weak 8 Finalizing: normal 7 Finalizing: normal 6 -- printing references -- Reference: null [WeakReference] Reference: soft 0 [SoftReference] Reference: weak 1 [WeakReference] Reference: soft 1 [SoftReference] Reference: null [WeakReference] Reference: soft 2 [SoftReference] Reference: weak 3 [WeakReference] Reference: soft 3 [SoftReference] Reference: null [WeakReference] Reference: soft 4 [SoftReference] Reference: null [WeakReference] Reference: soft 5 [SoftReference] Reference: null [WeakReference] Reference: soft 6 [SoftReference] Reference: weak 7 [WeakReference] Reference: soft 7 [SoftReference] Reference: null [WeakReference] Reference: soft 8 [SoftReference] Reference: null [WeakReference] Reference: soft 9 [SoftReference]
Weak references and normal objects are equally likely to be garbage collected but soft references live longer than them.
Soft reference only
In all above examples, we never saw a SoftReference was ever garbage collected. That's because GC will keep them as long as possible. GC will only start removing them when program has no more memory available and OutOfMemoryError situation is reached. At that point, GC will remove as many of them to avoid OutOfMemoryError.
Let's increase the number of iteration of our loop this time.
public class SoftOnly {
public static void main(String[] args) throws InterruptedException {
List<Reference<MyObject>> references = new ArrayList<>();
for (int i = 0; i < 100; i++) {
MyObject myObject = new MyObject("soft " + i);
Reference<MyObject> ref = new SoftReference<>(myObject);
references.add(ref);
//allocate a little slowly
Thread.sleep(10);
}
SoftVsNormal.printReferences(references);
}
} OutputFinalizing: soft 25 Finalizing: soft 7 Finalizing: soft 6 Finalizing: soft 5 Finalizing: soft 4 Finalizing: soft 3 Finalizing: soft 2 Finalizing: soft 1 Finalizing: soft 0 Finalizing: soft 16 Finalizing: soft 15 Finalizing: soft 14 Finalizing: soft 13 Finalizing: soft 12 Finalizing: soft 11 Finalizing: soft 10 Finalizing: soft 9 Finalizing: soft 8 Finalizing: soft 24 Finalizing: soft 23 Finalizing: soft 22 Finalizing: soft 21 Finalizing: soft 20 Finalizing: soft 19 Finalizing: soft 18 Finalizing: soft 17 Finalizing: soft 50 Finalizing: soft 49 Finalizing: soft 48 Finalizing: soft 47 Finalizing: soft 46 Finalizing: soft 45 Finalizing: soft 44 Finalizing: soft 43 Finalizing: soft 42 Finalizing: soft 34 Finalizing: soft 33 Finalizing: soft 32 Finalizing: soft 31 Finalizing: soft 30 Finalizing: soft 29 Finalizing: soft 28 Finalizing: soft 27 Finalizing: soft 26 Finalizing: soft 41 Finalizing: soft 40 Finalizing: soft 39 Finalizing: soft 38 Finalizing: soft 37 Finalizing: soft 36 Finalizing: soft 35 -- printing references -- Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: null [SoftReference] Reference: soft 51 [SoftReference] Reference: soft 52 [SoftReference] Reference: soft 53 [SoftReference] Reference: soft 54 [SoftReference] Reference: soft 55 [SoftReference] Reference: soft 56 [SoftReference] Reference: soft 57 [SoftReference] Reference: soft 58 [SoftReference] Reference: soft 59 [SoftReference] Reference: soft 60 [SoftReference] Reference: soft 61 [SoftReference] Reference: soft 62 [SoftReference] Reference: soft 63 [SoftReference] Reference: soft 64 [SoftReference] Reference: soft 65 [SoftReference] Reference: soft 66 [SoftReference] Reference: soft 67 [SoftReference] Reference: soft 68 [SoftReference] Reference: soft 69 [SoftReference] Reference: soft 70 [SoftReference] Reference: soft 71 [SoftReference] Reference: soft 72 [SoftReference] Reference: soft 73 [SoftReference] Reference: soft 74 [SoftReference] Reference: soft 75 [SoftReference] Reference: soft 76 [SoftReference] Reference: soft 77 [SoftReference] Reference: soft 78 [SoftReference] Reference: soft 79 [SoftReference] Reference: soft 80 [SoftReference] Reference: soft 81 [SoftReference] Reference: soft 82 [SoftReference] Reference: soft 83 [SoftReference] Reference: soft 84 [SoftReference] Reference: soft 85 [SoftReference] Reference: soft 86 [SoftReference] Reference: soft 87 [SoftReference] Reference: soft 88 [SoftReference] Reference: soft 89 [SoftReference] Reference: soft 90 [SoftReference] Reference: soft 91 [SoftReference] Reference: soft 92 [SoftReference] Reference: soft 93 [SoftReference] Reference: soft 94 [SoftReference] Reference: soft 95 [SoftReference] Reference: soft 96 [SoftReference] Reference: soft 97 [SoftReference] Reference: soft 98 [SoftReference] Reference: soft 99 [SoftReference]
This time some of the SoftReferences were garbage collected.
Conclusion
SoftReference: The underlying object can survive garbage collection's several cycles as long as the JVM is able to recover enough memory without throwing OutOfMemoryError. This makes them good candidate for keeping a memory-sensitive cache.
WeakReference: The underlying object can be garbage collected just like a normal object. It can be useful for situation when an object is used multiple times repeatedly during an event, but then, will likely to be used after a long time.
In both above cases, the program can recreate the underlying object whenever get() method returns null. This feature makes them being useful when comparing to normal object references.
Example ProjectDependencies and Technologies Used:
|