Author:
Kiran
•
Tuesday, February 12, 2008
Java is supposed to be an automatic memory managed environment. Or simply said, you can allocate memory and just forget to dispose it, explicitly. The virtual machine would take care of releasing it – a benign gesture towards a developer who can now afford to be more forgetful (without the fear of causing memory leaks), and hence more productive (?). Ignorance is Bliss!
But, there’s a catch! Of course, the virtual machine is not so smart. It does a fairly reasonable calculation to decide whether to release i.e., when there are no more references to that memory, it can be released. This implies that the memory is not recovered unless you nullify all the references to it.
Further, in case of real-world applications, with thousands of classes, it is highly likely that there might be some unknown stale references that are still lurking around in memory, preventing that memory from being recovered.
In essence, if the developer forgets to release all the references, it will not be reclaimed. It is not at all as benign as it was touted to be, after all. You still cannot afford to be forgetful - You have to nullify all those damn references!!
Author:
Kiran
•
Wednesday, October 03, 2007
If you are a software developer, invariably you would have come across some nasty bugs that wouldn’t just disappear so easily. They are elusive and hang around for days (or weeks), as if they are nagging at you. Remember those countless hours of debugging, stacked up coffee cups, working late nights – you are transformed into a workaholic.
When you are solving bugs, you either add new code or modify existing code. And, in the process, always run the risk of injecting new bugs, inadvertently. Thanks to Murphy’s law, these show stoppers show up exactly at the wrong time, threatening to derail the release. Again, the hapless developer is at the centre of the storm.
This is when those marathon debugging sessions start. Management does not leave any stone unturned in motivating the developer. “You have a golden opportunity knocking your door. This is your time to prove yourself. I am sure you will embrace this and live up to it. You will be a Hero! And your future glorious!” they would say. Not to mention, the poor developer falls prey yet again.
All pumped up, he sets off to squash the bug; nothing is difficult anymore. To start with, he inspects the logs. But, that wouldn’t reveal anything interesting. He inserts breakpoints at some obvious locations and checks the values of those global variables. They are just fine. Now, what about those third party libraries we are using. “I know that is where the bug is. My suspicion is true. Those laggards have a dubious reputation. Last time, it was there code that caused a lot of problems”.
He walks up to his manager to share his revelation, hoping that would be received well. “Well, just heard from quality folks that this feature was working on build dated 27-Sep. I think we used the same version of those libraries then. Didn’t we?” quips the manager. “Geee… You are right!”, he utters and walks back thinking to himself “How stupid I was. This isn’t as easy as I had thought”.
Now, free of inebriation, his sanity is restored. “I think we might have missed out on this one during the design”. He walks to the drawing board, to draw those architectural diagrams, hoping that would help him. As if that wasn’t all, the quality engineer drops in to provide some more 'interesting' piece of information. “The feature works perfectly with the current build, in the virtual machine. But, somehow the problem is seen only on physical machines” she says, with a sparkle in her eyes (that she might have just helped solve the mystery). Soon, the manager drops in with the latest update from the on-site team. “The problem is not seen in the current build on the physical machines running on Operating System X, while it is still observed on Operating System Y. Unfortunately, most our customers are running on Operating System Y. Good Luck!”.
No doubt there is a lot of information exchanged, a whole lot of such experiments conducted. These are only serving to add more variables to the equation, taking you further away from solution. Not knowing what to do next, he is on the verge of losing sanity. Not seeing anything that would come to his rescue, he digs deep, employs all those cool tools he had at his disposal. Several days of intense debugging, rewriting certain pieces of code, analyzing memory snapshots and CPU performance statistics at various intervals reveal that memory is getting corrupted. Further, analysis revealed that the thread from that third party library was populating the buffer faster than expected. The result was shared with the management. The third party admitted that the thread priority was changed in the last release. They promise to deliver a fix the next day.
Come next day, the problem is solved. Everybody is happy. Those 'MBA-Gods' in the top management, are all praises for the globally distributed effort to solve the crisis. Not to forget, “Good Job Done, Keep it up!” the gods blessed the developer!
Author:
Kiran
•
Thursday, September 13, 2007
Modern programming languages and their environments include Automatic Memory Management. For sure, the development community loves this cool feature; for it simply means that you can allocate as much memory as you want and then completely forget about releasing it!.
It is not just about the convenience, but has more – it helps programmers become more productive. Because, it allows them to concentrate better on the problem at hand, without having to keep track of the number of bytes they allocated and ensure that it is released. If they forget, well, tough luck, the memory just got leaked. Such bugs not only eat up memory and slow down the system, they are really hard to debug. It might eat up a few weeks in your schedule, if any such thing were to happen in a complex multi-threaded application, with a one thread allocation memory and a different one releasing it.
In case of managed environments like Java, the Garbage Collector 'frees' up memory that is no longer required i.e., there are no variables referring to the object’s memory – it can be reclaimed. The Java specification does provide a hook that allows us to 'resurrect' the objects that are about to be trashed.
According to the Java specification the object’s finalize() method is to be invoked, before reclaiming the object’s memory. The trick is to hoodwink the garbage collector by adding a reference to the object in the finalize() method. The following piece of code illustrates it:
import java.util.ArrayList;
public class Resurrect
{
private Resurrect anchor = null;
private String name = "";
private static ArrayList list = new ArrayList();
public Resurrect(String name)
{
super();
this.name = name;
}
public void finalize()
{
System.out.println(name + ": Finalize");
anchor = this;
// Add the object to the 'resurrection' list
list.add(this);
}
public void printMessage()
{
System.out.println(name + ": Am alive!!!");
}
private static void printList()
{
// Print all the 'resurrected' objects
for (int i = 0; i < list.size(); i++)
{
System.out.print(i + ": ");
Resurrect r = (Resurrect) list.get(i);
r.printMessage();
r.anchor.printMessage();
}
}
public static void main(String[] args)
{
Resurrect r1 = new Resurrect("r1");
Resurrect r2 = new Resurrect("r2");
// Deliberately switch r1 to refer r2, leaking r1.
r1 = r2;
// Explicitly invoke the Garbage Collector.
System.gc();
try
{
// Print the messages through both references
r1.printMessage();
r2.printMessage();
}
finally
{
try
{
/*
* Sleep to ensure that the current
* thread won't finish ahead of the
* Garbage Collector thread.
*/
Thread.sleep(5000);
}
catch (Exception e)
{
}
printList();
}
}
}