Showing posts with label gc / garbage collection. Show all posts
Showing posts with label gc / garbage collection. Show all posts

Saturday, 11 June 2011

Memory Leak : static collection object may be the reason

A very simple example of a memory leak would be a java.util.Collection object (for example, a HashMap) that is acting as a cache but which is growing without any bounds.
public class MyClass {
static HashSet myContainer = new HashSet();
public void leak(int numObjects) {
for (int i = 0; i < numObjects; ++i) {
String leakingUnit = new String("this is leaking object: " + i);
myContainer.add(leakingUnit);
}
}

Now in the main method:
public static void main(String[] args) throws Exception {
{
MyClass myObj = new MyClass();
myObj.leak(100000); // One hundred thousand }
System.gc();
}


In the above program, there is a class with the name MyClass which has a static reference to HashSet by the name of myContainer. In the main method of the class: MyClass, (in bold text) within which an instance of the class: MyClass is instantiated and its member operation: leak is invoked. This results in the addition of a hundred thousand String objects into the container: myContainer. After the program control exits the subscope, the instance of the MyClass object is garbage collected, because there are no references to that instance of the MyClass object outside that subscope. However, the MyClass class object has a static reference to the member variable called myContainer. Due to this static reference, the myContainer HashSet continues to persist in the Java heap even after the sole instance of the MyClass object has been garbage collected and, along with the HashSet, all the String objects inside the HashSet continue to persist, holding up a significant portion of the Java heap until the program exits the main method.

This program demonstrates a basic memory leaking operation involving an unbounded growth in a cache object. Most caches are implemented using the Singleton pattern involving a static reference to a top level Cache class as shown in this example.


Here is the GC information for you for the above snippet....

[GC 512K->253K(1984K), 0.0018368 secs]
[GC 765K->467K(1984K), 0.0015165 secs]
[GC 979K->682K(1984K), 0.0016116 secs]
[GC 1194K->900K(1984K), 0.0015495 secs]
[GC 1412K->1112K(1984K), 0.0015553 secs]
[GC 1624K->1324K(1984K), 0.0014902 secs]
[GC 1836K->1537K(2112K), 0.0016068 secs]
[Full GC 1537K->1537K(2112K), 0.0120419 secs]
[GC 2047K->1824K(3136K), 0.0019275 secs]
[GC 2336K->2035K(3136K), 0.0016584 secs]
[GC 2547K->2248K(3136K), 0.0015602 secs]
[GC 2760K->2461K(3136K), 0.0015517 secs]
[GC 2973K->2673K(3264K), 0.0015695 secs]
[Full GC 2673K->2673K(3264K), 0.0144533 secs]
[GC 3185K->2886K(5036K), 0.0013183 secs]
[GC 3398K->3098K(5036K), 0.0015822 secs]
[GC 3610K->3461K(5036K), 0.0028318 secs]
[GC 3973K->3673K(5036K), 0.0019273 secs]
[GC 4185K->3885K(5036K), 0.0019377 secs]
[GC 4397K->4097K(5036K), 0.0012906 secs]
[GC 4609K->4309K(5036K), 0.0017647 secs]
[GC 4821K->4521K(5036K), 0.0017731 secs]
[Full GC 4521K->4521K(5036K), 0.0222485 secs]
[GC 4971K->4708K(8012K), 0.0042461 secs]
[GC 5220K->4920K(8012K), 0.0018258 secs]
[GC 5432K->5133K(8012K), 0.0018648 secs]
[GC 5645K->5345K(8012K), 0.0018069 secs]
[GC 5857K->5558K(8012K), 0.0017825 secs]
[GC 6070K->5771K(8012K), 0.0018911 secs]
[GC 6283K->5984K(8012K), 0.0016350 secs]
[GC 6496K->6197K(8012K), 0.0020342 secs]
[GC 6475K->6312K(8012K), 0.0013560 secs]
[Full GC 6312K->6118K(8012K), 0.0341375 secs]
[GC 6886K->6737K(11032K), 0.0045417 secs]
[GC 7505K->7055K(11032K), 0.0027473 secs]
[GC 7823K->7374K(11032K), 0.0028045 secs]
[GC 8142K->7693K(11032K), 0.0029234 secs]
[GC 8461K->8012K(11032K), 0.0027353 secs]
[GC 8780K->8331K(11032K), 0.0027790 secs]
[GC 9099K->8651K(11032K), 0.0028329 secs]
[GC 9419K->8970K(11032K), 0.0027895 secs]
[GC 9738K->9289K(11032K), 0.0028037 secs]
[GC 10057K->9608K(11032K), 0.0028161 secs]
[GC 10376K->9927K(11032K), 0.0028482 secs]
[GC 10695K->10246K(11032K), 0.0028858 secs]
[GC 11014K->10565K(11416K), 0.0029284 secs]
[Full GC 10565K->10565K(11416K), 0.0506198 secs]
[GC 11781K->11071K(18956K), 0.0035594 secs]
[GC 12287K->11577K(18956K), 0.0042315 secs]
[GC 12793K->12082K(18956K), 0.0043194 secs]
[GC 12843K->12390K(18956K), 0.0030633 secs]
[GC 13606K->13494K(18956K), 0.0085937 secs]
[Full GC 13782K->13613K(18956K), 0.0646513 secs]

Tuesday, 24 May 2011

Java shutdown hooks

Java allows you to add shutdown hooks to your code. A shutdown hook is simply a thread that has been left in the initialized state. When your JVM is about to shutdown, the shutdown hook thread kicks in. The finalization processes of java objects run after the shutdown hooks complete. The JVM allows you to register more than one shutdown hook.

public class Task
{
public static void main(String[] args)
{
Runtime runtime = Runtime.getRuntime();
Thread thread = new Thread(new ShutDownListener());
runtime.addShutdownHook(thread);
someProcess();
}

private static void someProcess()
{
try
{
System.out.println("I am busy");
Thread.sleep(2000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}

class ShutDownListener implements Runnable
{
@Override
public void run()
{
System.out.println("I am shutting down");
}
}


The Task class is a simple class that runs a process. Once this process finishes up, we want the JVM to run a shutdown hook to notify us that the JVM is shutting down. When this program is run, the output is

I am busy
I am shutting down


The shutdown hook still executes. So the hook will execute even if there are errors / exceptions in the main program. What happens when the hook itself throws an error / exception ?. The uncaught exception will by default be printed to System.err and propagated to the VM. The behavior is comparable to a thread encountering an uncaught exception.

It seems pretty robust. However the shutdown hook is not guaranteed to execute. If a user closes the app abruptly or the VM crashes, or you click on the little red button on the eclipse console view, the shutdown hook will not run. It is not a good idea to use a shutdown hook to release critical resources (I have seen some code snippets that do this). It might end up not running and cause damage. The shutdown hook will execute only on normal termination or orderly shutdown.

Use the shutdown hook if you would like to do trivial operations with it. You can write code inside the hook that can clean up after the program (say delete a temporary file). Or write a bye bye message. The code inside the hook should not do critical things like release DB connections that your program acquired. Doing something like that is asking for trouble, since this code may never run.

Also keep in mind that hooks run concurrently. Each hook is registered as a Thread with the VM and each Thread will run in parallel with the other hooks. If the hooks synchronize over resources incorrectly you will end up dead locking the application.

The hooks also need to finish up quickly. If they do not, that poses a problem. The application will wait for ever to exit gracefully.

So now you know what shutdown hooks are and how to use them, if you ever need to.

In Summary


  • Do not write shutdown hooks to do critical tasks
  • Make sure your shut down hooks complete quickly
  • Consider using one shutdown hook instead of several. If you decide to use several shutdown hooks, make their activities thread safe.
  • Hook code flow should not depend on the method in which the application was shutdown. How an application terminates is never guaranteed.

Monday, 23 May 2011

Java interview questions on garbage collections

Which part of the memory is involved in Garbage Collection? Stack or Heap?

Ans) Heap

What is responsiblity of Garbage Collector?

Ans) Garbage collector frees the memory occupied by the unreachable objects during the java program by deleting these unreachable objects.
It ensures that the available memory will be used efficiently, but does not guarantee that there will be sufficient memory for the program to run.

Is garbage collector a dameon thread?

Ans) Yes GC is a dameon thread. A dameon thread runs behind the application. It is started by JVM. The thread stops when all non-dameon threads stop.

Garbage Collector is controlled by whom?

Ans) The JVM controls the Garbage Collector; it decides when to run the Garbage Collector. JVM runs the Garbage Collector when it realizes that the memory is running low, but this behavior of jvm can not be guaranteed.
One can request the Garbage Collection to happen from within the java program but there is no guarantee that this request will be taken care of by jvm.

When does an object become eligible for garbage collection?

Ans) An object becomes eligible for Garbage Collection when no live thread can access it.

Can the Garbage Collection be forced by any means?
Ans) No. The Garbage Collection can not be forced, though there are few ways by which it can be requested there is no guarantee that these requests will be taken care of by JVM.

How can the Garbage Collection be requested?

Ans) There are two ways in which we can request the jvm to execute the Garbage Collection.

  • 1) The methods to perform the garbage collections are present in the Runtime class provided by java. The Runtime class is a Singleton for each java main program.
    The method getRuntime() returns a singleton instance of the Runtime class. The method gc() can be invoked using this instance of Runtime to request the garbage collection.
  • 2) Call the System class System.gc() method which will request the jvm to perform GC.

What is the purpose of overriding finalize() method?

Ans) The finalize() method should be overridden for an object to include the clean up code or to dispose of the system resources that should to be done before the object is garbage collected.

If an object becomes eligible for Garbage Collection and its finalize() method has been called and inside this method the object becomes accessible by a live thread of execution and is not garbage collected. Later at some point the same object becomes eligible for Garbage collection, will the finalize() method be called again?
Ans) No

How many times does the garbage collector calls the finalize() method for an object?
Ans) Only once.

What happens if an uncaught exception is thrown from during the execution of the finalize() method of an object?
Ans) The exception will be ignored and the garbage collection (finalization) of that object terminates.

What are different ways to call garbage collector?
Ans) Garbage collection can be invoked using System.gc() or Runtime.getRuntime().gc().

How to enable/disable call of finalize() method of exit of the application
Ans) Passing the boolean value will either disable or enable the finalize() call.

Runtime.getRuntime().runFinalizersOnExit(boolean value) . 

Sunday, 15 May 2011

Disadvantage of Garbage collection

A potential disadvantage of a garbage-collected heap is that it adds an overhead that can affect program performance. The Java virtual machine has to keep track of which objects are being referenced by the executing program, and finalize and free unreferenced objects on the fly. This activity will likely require more CPU time than would have been required if the program explicitly freed unnecessary memory. In addition, programmers in a garbage-collected environment have less control over the scheduling of CPU time devoted to freeing objects that are no longer needed.

Advantage of garbage collection

Garbage collection relieves you from the burden of freeing allocated memory. Knowing when to explicitly free allocated memory can be very tricky. Giving this job to the Java virtual machine has several advantages. To list few :

  1. It can make you more productive. When programming in non-garbage-collected languages you can spend many late hours (or days or weeks) chasing down an elusive memory problem. When programming in Java you can use that time more advantageously by getting ahead of schedule or simply going home to have a life.
  2. A second advantage of garbage collection is that it helps ensure program integrity. Garbage collection is an important part of Java's security strategy. Java programmers are unable to accidentally (or purposely) crash the Java virtual machine by incorrectly freeing memory.

Object destruction and the finalize method

The aim of destructor in any OOPs language is:

  1. Free up the memory (c++ suffer from memory allocation / deallocation)
  2. Clean up any other resources (like closing of open file stream)

Java take cares of all and hence there is no destructor in JAVA. (With the help of Garbage collection) but still if you want to perform some additional tasks, then you can use the finalize() method of java.

But, we can’t rely on finalize() as it depends on GC. Sometimes, GC may never be invoked during the lifetime of the program. A good idea is to implement a method, say cleanUp() which does, any special processing required, ofcourse, other than freeing up memory. The programmer should call this method at the approppriate place in the program. That is the only way to make sure your program works correctly.

Example code of finalize in java:

class HasFinalize{

public static int number_of_things = 0;
public String what;

public HasFinalize(String what) {
this.what = what;
number_of_things++;
}

protected void finalize () {
number_of_things--;
}
}

public class TestFinalize {
public static void main(String[] args)
{
Thing obj = new Thing("Test App");

}
}


The method call System.runFinalizersOnExit(true) guarantees that finalizer methods are called before Java shuts down. However, this method is inherently unsafe and has been deprecated. An alternative is to add "shutdown hooks" with the method Runtime.addShutdownHook—see the API documentation for details.

 

If a resource needs to be closed as soon as you have finished using it, you need to manage it manually. Supply a method such as dispose or close that you call to clean up what needs cleaning. Just as importantly, if a class you use has such a method, you need to call it when you are done with the object.

Saturday, 14 May 2011

How substring() works in java?

substring() is a function to get substring from string. A String class is immutable in java.
A String can be implemented as an object with three fields ( normal string class have even more, but consider 3 for now) -- a character array, an offset into that array, and a length.
Consider the following code
String s1 = "Monday";
String s = s1.substring(0,3);
or
s1.substring(0,3).equals("Mon");

substring() creates a new String and returns it back. But substring is clever. It does not make a deep copy of the substring the way most languages do. It just creates a pointer into the original immutable String, i.e. points to the value char[] of the base string, and tracks the starting offset where the substring starts and count of how long the substring is. So only length and offset are different per string but the character array is shared with the original string class. This can be shown in figure:
substring-buffer-java


The downside of this cleverness is a tiny substring of a giant base String could suppress garbage collection of that big String in memory even if the whole String were no longer needed. (actually its value char[] array is held in RAM; the String object itself could be collected.)
If you know a tiny substring is holding a giant string in RAM, that would otherwise be garbage collected, you can break the bond by using

String s = new String(s1.substring(0,3));

Saturday, 30 April 2011

About Daemon Threads in Java

There can be two types of threads in Java viz User Thread and Daemon Thread. All the threads created by a user are user threads. A thread becomes Daemon thread when the user says so. User threads are meant for the program code.

On the other hand Daemon threads are service provider threads. They should not be used to run your program code but some system code. The run() method for a daemon thread is typically an infinite loop that waits for a service request. These threads run in parallel to your code but survive on the mercy of the JVM. When JVM finds no user threads it stops and all daemon threads are terminated instantly. Thus one should never rely on daemon code to perform any program code.

For better understanding consider a well known example of Daemon thread : Java garbage collector. The Garbage collector runs as a low priority daemon thread to reclaim any unused memory. When all user threads terminates, JVM may stop and garbage collector also terminates instantly. 

Daemon threads are typically used to perform services for your application/applet. The core difference between user threads and daemon threads is that the JVM will only shut down a program when all user threads have terminated. Daemon threads are terminated by the JVM when there are no longer any user threads running, including the main thread of execution. Use daemons as the minions they are. This makes sense because when only daemon threads remain, there is no other thread for which a daemon thread can provide a service.

To specify that a thread is a daemon thread, call the setDaemon() method with the argument true. To determine if a thread is a daemon thread, use the accessor method isDaemon().

Sunday, 17 April 2011

Weakhashmap : When value depends on key

Consider the following code:

import java.util.Map;
import java.util.WeakHashMap;

public class TestWeakHeakHashMap
{
private String name = new String("java");
private Map cache = new WeakHashMap<String, DependentObject>();

public void testMethod()
{
cache.put(name, new DependentObject("1", name));

//Discard the strong reference to the key
name = null;
while (true) {
System.gc();
/**
          * Verify Full GC with the -verbose:gc option
            Since there is no strong reference to the key, it is assumed that the
            entry has been removed from the WeakHashMap
          */
System.out.println(cache.size());
}
}

private class DependentObject
{
private String id;
private String name;

public DependentObject(String id, String name)
{
this.id = id;
this.name = name;
}
}
}

Now when the testMethod() is run what do you expect the output to be? Since the strong reference to key is discarded, we assume that the entry from the map would be removed, and map would be empty after a full GC.
But that does not happen though.

Let us see what was the put operation on the WeakHashMap.

cache.put(name, new DependentObject("1", name));


Here the value DependentObject was holding the key name. This would mean that the value always strongly refers to the key, and hence the key would never be garbage collected. The entry would always remain the map.

This is what WeakHashMap API says - "The value objects in a WeakHashMap are held by ordinary strong references. Thus care should be taken to ensure that value objects do not strongly refer to their own keys, either directly or indirectly, since that will prevent the keys from being discarded."

Weakhashmap : Using string from literal pool as key

Consider the following code snippet:
public class TestWeakHashMap
{
private String str1 = new String("newString1");
private String str2 = "literalString2";
private String str3 = "literalString3";
private String str4 = new String("newString4");
private Map map = new WeakHashMap();

private void testGC() throws IOException
{
map.put(str1, new Object());
map.put(str2, new Object());
map.put(str3, new Object());
map.put(str4, new Object());

/**
        * Discard the strong reference to all the keys
        */
str1 = null;
str2 = null;
str3 = null;
str4 = null;

while (true) {
System.gc();
/**
            * Verify Full GC with the -verbose:gc option
            * We expect the map to be emptied as the strong references to
            * all the keys are discarded.
            */
System.out.println("map.size(); = " + map.size() + " " + map);
}
}
}

What do we expect the size of the map to be after full GC? I initially thought it should be empty. But it turned out to be 2.

Look at the way the four Strings are initialized. Two of them are defined using the 'new' operator, whereas the other two are defined as literals. The Strings defined using the 'new' operator would be allocated in the Java heap, but the Strings defined defined as literals would be in the literal pool.
The Strings allocated in the literal pool (Perm Space) would never be garbage collected.
This would mean that String 'str2' and 'str3' would always be strongly referenced and the corresponding entry would never be removed from the WeakHashMap.

So next time you create a 'new String()' , put it as a key in a WeakHashMap, and later intern() the String, beware - Your key will always be strongly referenced.

Invoking intern() method on a String will add your String to the literal pool if some other String equal to this String does not exist in the pool
private String str5 = (str4+str1).intern();

WeakHashMap in java : Soft reference based hashmap

A WeakHashMap stores the keys using WeakReference objects, which means that as soon as the key is not referenced from somewhere else in your program, the entry may be removed and is available for garbage collection. Otherwise it is similar to HashMap.

One of the most common instances of memory leaks in Java is in hash maps, so Sun Microsystems (now Oracle) has provided a WeakHashMap to minimize memory usage in caches implemented with maps. A WeakHashMap stores the keys using WeakReference objects, which means that as soon as the key is not referenced from somewhere else in your program, the entry may be removed and is available for garbage collection. (Have a look at the JavaDocs for the java.util.WeakHashMap and java.lang.ref.WeakReference for more information). It is important to note that the WeakHashMap has a WeakReference to the key—rather than, as we would expect—the value.

Read about type of references here.
 
As the garbage collector may remove keys from the WeakHashMap and garbage collect the object, outputs from methods like size() , isEmpty() may vary with time. The size( ) method may return different values over time. The isEmpty( ) method may return false and then true.
 
Note: Value objects in the WeakHashMap will be garbage collected only if their key is removed and they have no other reference to them. It should be noted that if the value object has a reference to its own key object, the key objetc will not be garbage collected. This situation should be avoided.

WeakHashMap Example:
public class TestWeakHashMap {
public static void main(String[] args) {
WeakHashMap map=new WeakHashMap();

String s1=new String("java");
map.put(s1, "good");
String s2=new String("java");
map.put(s2,"ok");

//Since s1.equals(s2) is true and hash is same, the earlier value
//against key s1 ("good") in the map is replaced by the new one. ("ok")

s1=null;

System.gc();
//Verify Full GC with the -verbose:gc option

System.out.println(map.size());
}
}


Here s1 and s2 are two different objects on the heap. So in line 5, a new (key,value) pair with key s1 is put into the map. Later when a (key,value) with key s2 is being put into the map, it checks for equals on s1 and s2 and their hashcode. When it finds the equals returns true and hashCode is same, it replaces the value of the earlier entry with the new value. But the issue here is, WeakHashMap/HashMap does not replace the earlier key while adding a (key, value) pair whose key is actually a duplicate key in the map.
So even after putting an entry with key s2, the WeakHashMap has only one entry whose key refers to the object refered by s1 and not s2.

Now the object on the heap refered by s1, has one strong reference(through s1) and one weak reference through the WeakHashMap.
Later when I say s1=null, the object on the heap refered to by s1 lost the strong reference and when gc happens, the entry is removed from the map.

So thats how it works.

Also note WeakHashMap is only a wrapper over HashMap and the HashMap's put api says " If the map previously contained a mapping for this key, the old value is replaced by the specified value."

Also see -

Wednesday, 1 September 2010

Deterministic lifetime of object in c++ as compared to java

C++ approach of Object Destruction

Some object-oriented programming languages, notably C++, have explicit destructor methods for any cleanup code that may be needed when an object is no longer used. The most common activity in a destructor is reclaiming the memory set aside for objects. Because Java does automatic garbage collection, manual memory reclamation is not needed and so Java does not support destructors.
Of course, some objects utilize a resource other than memory, such as a file or a handle to another object that uses system resources. In this case, it is important that the resource be reclaimed and recycled when it is no longer needed.
So cpp follows deterministic approach of object destruction.

Java Approach of object destruction

Java's approach is automatic garbage collection. You can add a finalize method to any class. The finalize method will be called before the garbage collector sweeps away the object. In practice, do not rely on the finalize method for recycling any resources that are in short supply—you simply cannot know when this method will be called. So java follows non-deterministic approach.

Advantage of Garbage collection

See here for advantage of garbage collection.

Disadvantage of Garbage collection

See here for disadvantage of Garbage collection

 

Final note

Garbage collection has increased problem, rather than solving many. Due to limited memory, we can get out of memory error. But this problem or disadvantage, we have to live with java.