Efficient Memory Management in Java - Article 1
In our day to day life , we deal with classes , objects and functions in the world of java . These are pretty much the things which full fills all are daily needs with the help of different design patterns and programming standards. In most of the work we do performance has been the criteria for most of our application , but normally time takes the precedence over space. Due to which we sometimes end up issues related to memory.
As we know Java is language which takes a huge heap over other languages like C and C++ with respect to memory management. We are no longer required to allocate and de-allocate memories in java . During the java's life cycle , memory management has evolved a lot with more intelligence being inducted in JVM and GC (Garbage Collector). In the recent version of JDK (JDK 7) , a completely new Garbage collector Algo (G1) has been introduced.
Now the big question : THEN WHY DO WE STILL GET MEMORY EXCEPTION
There are 2 main reasons
- Bad coding practices : Every java developer does this , in some way or the other.
- GC is unpredictable : Java provide certain guarantee regarding its GC but it's purely
impossible to predict the GC operation at a given time.
We won't dig deep here with respect to Point (1) . This could be eradicated by using proper coding standards , effective code review and even by using external tools for Memory management
Coming to Point (2) , As mentioned earlier its impossible to predict the GC operation at a given time . The reason being very clear that , GC internally depends on OS scheduling mechanism and OS memory management which is not controlled by Java . Said this java provides us with certain mechanism which can make our life easy regarding Memory management. And the most important of them is References
Short Description on GC in Java
Not digging deep , GC mechanism contains basically 3 steps
- Checking if object is not reachable , if Yes
a) Check if object implements finalize() method , if so add to finalization queue
b) Else , make the object finalized
2) If (a) section of Point (1) was true , then pick the object from finalization queue and run the finalize method and make object finalized
3) Garbage collector picks the object and de–allocates the memory
**(GC is a detailed topic and would be picked up in coming up journals)
Jumping to References in Java
References as going by Wikipedia 'is a relation between objects in which one object designates' and nothing changes in java.
Before Jumping into the references , we need to know about reference Queue
ReferenceQueue as java doc says 'to which registered reference objects are appended by the garbage collector ' . So at a point when GC realizes that any of the reference to which it is listening is ready for garbage collection. GC inserts that particular object into Reference Queue .
There are basically 4 time of Reference in java . In this article , we would be focusing mainly on
2 type of reference
a) Strong reference :
These are most common and widely used references .
public List obj1=new ArrayList();
Here obj1 is a strong reference and GC can't in any case de-allocate the memory grabbed by ArrayList until obj1 doesn't gets unreferenced ( goes out of scope) or at least it starts pointing to another object .
But these references might not be the best choice . Specially , when you have heavy data lying in your memory like a File Object ,a heavy database result set etc.
This is the place where other options come into picture
b) Weak References :
As java doc says : 'Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed '.
As the name suggest ,it sets up a weak reference to an object . For e.g.
The first parameter (k) is the object on which weak reference is being created and the second one is the Reference Queue (rq)
As we know, its difficult to understand this concept without digging into the code , so lets pic one simple example .
We would be needing 2 simple POJO's as helper classes for our example.
Now lets come to a simple weak Reference article
Now lets go point by point
Initially we create 2 strong references for KeyBean and KeyBeanParent parent.
(1) – As you could see KeyBeanParent reference class has a Weak Refernce object for
KeyBean , so we would assign the same object of KeyBean created just above to the instance of KeyBeanParent . A point to note here is we are not assigning any reference , because usage of reference queue is optional and WeakReference class
provides us with 2 different constructors .
(2) – We create a new instance of Reference Queue
(3) – This is the place where we create a weak reference and attach the previously created queue
(4) - Now we hit first print statement , as you can compare with the output section , wf.get() returns the original object on which this weak reference was created
(5) - This is where the weak reference concept actually begins, at this point we simply set the reference to null and making the referenced object only reachable through 2 weak reference , one from wf in the main method and one under p ( KeyBeanParent) object's kb reference
(6) & (7) - At this place , we try print the values from the respective weak references and as you could see from the output section that , both then returns the same object. This is due to the fact that GC probably hasn't run after setting the value to null.
(8) - In next step we notify GC to run explicitly ( as we understand , its just a notification and doesn't ensure that GC would run , but in this case as the load is least , so we notice that GC actually run ( This is pure co-incidence and can't be relied upon) .
(9) & (10) - Here we try to print the value from weak references and we notice that (from output ) section that these values are null.
(11) & (12) - As GC puts the weak reference into Refrence Queue , we can get it out using methods like poll and remove them and print it.
Summarizing Story of WeakRefrence
Whenever GC finds that any particular object on heap doesn't have a strong reference or soft reference** but is reachable through weak reference , then it picks up this weak reference , disconnects it with the object and insert this weak reference into the Reference Queue (if any) . The Object now id ready for the process of Garbage collection.
** Soft Reference would be a part of next article , for now you could assume it to be another form of reference.
Why do we need Weak Refernce
This answered by Java in its own SDK . WeakHashMap , is one of the classes which leverages this concept . As per documentation of Java for this class , it says , WeakhashMap is pretty similar to HashMap , only difference being that keys are weak references.
Now the question is why do we need it – Lets take an example , If suppose you are loading a gif format file and we know the size of these files can shoot up-to 5 MB . So we decide to keep this object in a map with a key and value pair . Now once the use of this map object is over , we are responsible to remove it. Now this is a additional functionality we need to implement and manage. But this could be avoided using weakhashmap , once the GC realizes that there is no strong reference to the key , then it would , internally release the weak key from the map and that gif object is released from memory.
In the next article , we would discuss about Phantom and Soft references.