Java Weak Reference, Soft Reference, Phantom Reference, Hard Reference | Heap & GC Behavior with example

In this article we will compare Java Hard Reference, Weak Reference, Soft Reference, Phantom Reference along with example and monitor heap usage & garbage collection behavior for these references under heavy load.

How will we test heap usage & GC behavior?

  • Create Lots of object: We will create lots of custom objects with heavy data in it so that it will consume observable heap memory.
  • Create References: We will point hard/soft/weak/phantom references to above objects.
  • Retain all references: We will put all above references in a static ArrayList instance so that all references will be retained in heap till program is running.
  • Test with limited memory: We will test this program with limited heap memory of 50 MB so that we will have smaller observation set. We will use these java options for this -Xmx50m -XX:MaxMetaspaceSize=50m
  • Monitor heap & GC: As per the documentation of references, objects might be garbage collected as per specification. We will use JMX console to monitor heap usage & garbage collection behavior.

We will use object of below class to point reference to. These objects will have a ‘heavyLoad’ which is just a huge String made from ‘name’. This is to make object heavy so that we can observe heap usage & GC behavior.



Hard Reference

Hard reference is most basic variable reference in Java. As long as these references are retained in any way, objects are not considered eligible for garbage collection.

Execute program with 50 MB heap & same metaspace.

Program waits 30 seconds at start so that you can get enough time to open JMX console. Open jconsole.exe from JDK (On windows, C:\Program Files\Java\jdk-11.0.1\bin). Connect to running program, go to ‘Memory’ tab & select “Heap Memory Usage” in chart dropdown.

Observations:

  • You can see in above graph, as program continues to run, heap usage kept on growing & there is almost no drop in heap usage anywhere.
  • Eventually program ended with java.lang.OutOfMemoryError: Java heap space  & JVM ended.
  • You can see that JVM spent entire 1 minute on OLD generation GC collection out of ~3 min program which shows that GC had hard time collecting objects.
  • There were 2733 GC old collection but as per graph there was no luck in collecting any objects (as expected in this example)



Soft Reference

Soft references are special references in Java. Objects referenced by SoftReference are supposed to be biased against clearing recently created soft reference. As per javadoc of SoftReference, “Virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references.”. So its safe to say that as long as object of only softly referenced & not recently used or created, it will be eligible for garbage collection & finalization.

Execute program with 50 MB heap & metaspace.

Observations:

  • You can see in above graph, as program continues to run, heap usage kept on peaking beyond 40 MB & then dropped several times due to GC collections. So JVM did not collect objects unless heap usage was nearing 40MB & above i.e. closer to max heap 50 MB.
  • Program continued execution without any issues but objects started finalizing bit later in time as per logs.
  • You can see that JVM spent more time in young generation (May be collecting lot of Stings we created) i.e. 1 minute with whopping ~78 thousands collections in span of ~ 4 minutes.
  • There were several objects made it to old generation (most probably soft references) & they were easily collected in just 36 collections which took ~2 seconds. So GC did not have much difficulty.



Weak Reference

Objects pointed by weak references are made eligible for garbage collection when only referenced by weak reference without any bias like soft reference. So it is upto JVM to unconditionally decide when to collect weak referenced object.

Observations:

  • You can see in above graph, as program continues to run, heap usage kept on peaking anywhere between 20 MB till ~40 MB. Heap usage dropped even when it was below 30 MB. There are several drops below 40 MB or even below 30 MB which means GC happened even when it wasn’t nearing max heap usage.
  • Program continued execution without any issues & objects started finalizing almost immediately as per logs.
  • You can see that JVM spent ~30 seconds in young generation collection with ~ 32 thousands collections.
  • There were literally 0 collections in old generation as probably most of the weak references were getting collected in young generation.



Phantom Reference

As per javadoc documentation of PhantomReference, “Phantom references are most often used to schedule post-mortem cleanup actions.”. Phantom reference objects are mainly meant for cleanup so they are eligible to garbage collection & finalization almost immidiately after being only referenced by phantom reference. You can never retrieve object from phantom reference.

Observations:

  • You can see in above graph, as program continues to run, heap usage kept on peaking anywhere between 20 MB till ~40 MB. Heap usage drops seems more frequent than weak references.
  • Program continued execution without any issues & objects started finalizing almost immediately as per logs.
  • You can see that JVM spent ~35 seconds in young generation collection with ~ 38 thousands collections.
  • There are literally 0 collections in old generation as probably most of the phantom references were getting collected in young generation.



Watch test in action

Here is a video of execution of all above tests with running logs & live heap usage graph in JMX console. Graphs might vary a bit as its a separate run.



Leave a Reply

Your email address will not be published. Required fields are marked *