Tuesday, June 14, 2011

Garbage collection with Automatic Resource Management in Java 7

This post provides a brief overview of a new feature introduced in Java 7 called Automatic Resource Management or ARM. The post delves how ARM tries to reduce the code that a developer has to write to efficiently free the JVM heap of allocated resources.

One of the sweetest spots of programming in the Java programming language is automatic handling of object de-allocation. In Java world this is more popularly known as garbage collection; it basically means that developers do not have to worry about de-allocating the object allocated by their code. As soon as a developer is finished with using the object he can nullify all references to the object and then the object becomes eligible for garbage collection.

Garbage collection has a flip side to it however. Unlike in C/C++ where the coder has complete control of memory allocation and de-allocation [malloc, free, new, delete etc], in Java the developer does not have significant control over the process of de-allocation of objects. The JVM manages the process of garbage collecting of unused objects and it is really up to the whims of the JVM when to run a cycle of garbage collection. True, there are method calls like System.gc() or Runtime.getRuntime().gc() that indicates that garbage collection will be run, but these methods merely serve to remind the JVM that -"maybe you need to run a garbage collection now, just a suggestion, no pressure!". The JVM is fully authorized to disregard such requests and is coded to run garbage collection only when it really sees fit. Hence in practice, developers are always advised not to build their program logic believing System.gc() or Runtime.getRuntime().gc() will trigger a full garbage collection.

There is no denying how much good automatic garbage collection has done to enhance the productivity of developers. However there are some corner cases where garbage collection is not sufficient to mantain a "clean" heap, free of unused objects. Especially if the objects deal with some form of native resources that is served by the underlying operating system. These objects include, but are not limited to IO streams, database connections etc. For these kind of objects developers must release the resources explicitly. Typically these are done through try-catch blocks.

Let us look at a small example that closes an InputStream after finishing the processing of the stream:
InputStream in = null;

try
{
    in = new FileInputStream(new File("test.txt");
    //do stuff with in
}
catch(IOException ie)
{
    //SOPs
}
finally
{
    //do cleanup
}
The above looks good and clean; however as soon as we try to close the input stream via in.close() in the finally block, we need to surround it with a try-catch block that catches the checked exception, IOException. Thus the code sample transforms to:
InputStream in = null;

try
{
    in = new FileInputStream(new File("test.txt"));
    //do stuff with in
}
catch(IOException ie)
{
    //SOPs
}
finally
{
    try
    {
        in.close();
    }
    catch(IOException ioe)
    {
        //can't do anything about it
    }
}
Now the above code looks bloated, and with multiple kinds of checked exceptions in different hierarchy, we need more catch clauses. Very soon the code becomes lengthy and difficult to maintain, not to mention the code losing its initial clean and no-nonsense look that even appealed to the eye.

But there is a good news.

Java 7 makes this easier with the new try-catch block. With this feature we can avoid the finally block itself. This is how we do it:
try(InputStream in = new FileInputStream(new File("test.txt"))
{
    //do stuff with in
}
catch(IOException ie)
{
    //SOPs
}
The above block of code will do the cleanup part itself. This is made possible by the introduction of a new interface, java.lang.AutoCloseable which defines a single method, void close() throws Exception. Objects which are subtypes of this interface can be automatically close()d using the above syntax. The above feature is applicable to objects of any class that implement the AutoCloseable interface.

The best part is that even if we initialize multiple AutoCloseable instances in the try() block, it will call the close() method for all the objects, even if some close() method on some object throw any exception.

Coming to the handling of the exceptions, if there was any IOExceptions in our try block as well as in the implicit finally block [where the AutoCloseables are actually being close()ed], the exception thrown will be the one that was thrown in the try block rather than the one in the implicit finally block.

However we can still have the details of the implicit finally block's exception from the method Throwable.getSuppressed() which is added as a new method in Java 7.

I think Automatic Resource Management feature, or ARM is a great addition to Java 7.

Happy coding!!

14 comments:

  1. Amazing feature something java desperately needed and an answer to all those questions related to checked exception polluting java codes. I have never been a big fan of checked Exceptions and prefer RuntimeException due to same reason but looks like after 6 version Java guys are making some progress in this direction. by the way nice post and look forward to some more post about new feature in Java 7.
    How Garbage collection works in Java

    ReplyDelete
  2. Thank you for your feedback! Will try to come up with more posts on such topics.

    ReplyDelete
  3. Your code would be a lot cleaner if you just used try/finally and leave it to some higher level to catch any exceptions. Mixing try/catch/finally isn't generally useful because they operate on different levels. try/finally (or just the new try) are for resource management--that's what you need to do at the level at which you do the actions that might throw exceptions. But try/catch is at the level where you actually know what to do about the exceptions--tell the user, retry, or whatever. So, your typical pattern should be

    ResultType process(String filename) throws IOException
    {
    try (InputStream in = new FileInputStream(new File(filename))
    {
    ...
    }
    }

    ReplyDelete
  4. First of all, I cannot believe that I am actually replying to a comment by a person, whose books form the foundation of whatever I know about the Java language today!

    Yes, that seems a better approach. I put my code as I did because in most cases even if we do not do anything about an exception in the catch clause, we at least do a logger.error() or wrap the more specific exception [eg SQLException] by a more generic/custom exception [eg DatabaseException]. That was why I kept the catch clause, but as you said, if we do opt to do nothing about the exception we might as well remove the catch clause.

    ReplyDelete
  5. Automatic Resource Management in Java 7 is very similar with C# using construct ... At the end of the using block, the object is deallocated - it must only implement the IDisposable interface.

    ReplyDelete
  6. Nice to know that. Does it work with locks? For example, take a lock of an object at the beginning of the block and automatically release it at the end. I am not familiar with C# though.

    ReplyDelete
    Replies
    1. Looking at the javadoc for Java 7's Lock interface it doesn't appear to implement the java.lang.AutoCloseable interface. Shame really.

      Reference:
      http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html

      Delete
  7. Nice post...even I used to forget closing the connections or closing the files sometimes and the problem is resolved with Java7.
    But one problem still persists that what if we want to do something else in destructor like we have a static variable for counting the number of objects in that case even if we decrease the number of objects by one in finalize method and we declare the object reference as null the GC will be called at its own time the the number of objects will be in illegal state during that time.

    ReplyDelete
  8. For starters, we should never use finalize for counting "active" objects. We can do this by using a WeakHashMap to store the references of the allocated objects. You will have to do this in the constructor of your object. Basically for every object allocated, you have to add that reference to the static WeakHashMap. This has the following advantages:

    1. There will be no memory leaks. Since the references are weak.

    2. You will always have a updated count for the number of active objects. [use map.size() to get the current count]

    You will have to take proper care in synchronizing access to the map.

    ReplyDelete
  9. So if you have several resources you need to put them in ever increasing try blocks - wow, that solves the close problem!

    ReplyDelete
  10. Hi dear it's awesome post.
    It's great stuff i really like it.Human Resource Management

    ReplyDelete
  11. Hi dear it's awesome post.
    It's great stuff i really like it.Human Resource Management

    ReplyDelete
  12. Hi Swaranga,

    I am facing Java Heap Error. I have around 8500 lines in a .csv format and i m appending 40 more values one by one to each line in a StringBuilder object so i m running the loop around 4 lakh times. As a result i m getting Java Heap Error. Is there any way i can avoid this. Plz help. reply asap.

    Regards//
    Prateek
    8527592376
    appcrazyprateek@gmail.com

    ReplyDelete