Showing posts with label reference. Show all posts
Showing posts with label reference. Show all posts

Thursday, 22 December 2011

Avoid memory leaks using Weak&Soft references

Some Java developers believe that there is no such a thing as memory leak in Java (thanks to the fabulous automatic Garbage Collection concept)

Some others had met the OutOfMemoryError and understood that the JVM has encountered some memory issue but they are not sure if it’s all about the code or maybe even an OS issue…

The OutOfMemoryError API docs reveals that it “Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector. “

As we know, the JVM has a parameter that represents the maximum heap size(-Xmx), hence we can defiantly try to increase the heap size. yet some code can generate new instances all the time, if those instances are accessible(being referenced by the main program – in a recursive manner) for the entire program life span, then the GC won’t reclaim those instances. hence the heap will keep increasing and eventually a OutOfMemoryError will be thrown <- we call that memory leak.

Our job as Java developers is to release references (that are accessible by the main program) that we won’t use in the future. by doing that we are making sure that the GC will reclaim those instances (free the memory that those instances occupying in the heap).

In some cases we reference an instance from 2 different roots. one root represent a fast-retrieval space(e.g. HashMap) and the other manages the real lifespan of that instance. Sometimes we would like to remove the reference of that instance from one root and get the other root(fast retrieval) reference removed automatically.

We wouldn’t want to do it manually due to the fact that we are not C++ developers and we wouldn’t like to manage the memory manually..

Weak references

In order to solve that we can use WeakReference.

Instances that are being referenced by only Weak references will get collected on the next collection! (Weakly reachable), in other words those references don’t protect their value from the garbage collector.

Hence if we would like to manage the life span of an instance by one reference only, we will use the WeakReference object to create all the other references.

( usage: WeakReference wr = new WeakReference(someObject);)

In some apps we would like to add all our existing references to some static list, those references should not be strong, otherwise we would have to clean those references manually, we would add those references to the list using this code.

public static void addWeakReference(Object o){
refList.add(new WeakReference(o));
}


since most of the WeakReferences use cases needs a Map data structure, there is an implementation of Map that add a WeakReference automatically for you – WeakHashMap

Soft References

I saw few implementations of Cache using weak references (e.g. the cache is just a WeakHashMap => the GC is cleaning old objects in the cahce), without WeakReferences naive cache can easily cause memory leaks and therefor weak references might be a solution for that.

The main problem is that the GC will clean the cached-object probably and most-likely faster then you need.

Soft references solve that, those references are exactly like weak references, yet the GC won’t claim them as fast. we can be sure that the JVM won’t throw an OutOfMemory before it will claim all the soft and weak references!

using a soft references in order to cache considered the naive generic cache solution. (poor’s men cache)

( usage:SoftReference sr = new SoftReference(someObject);)

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();

Reference types in java

Following the references common in java - strong,soft,weak and phantom.

You can think of direct references as strong references that require no extra coding to create or access the object. The remaining three types of references are subclasses of the

Reference class found in the java.lang.ref package. Soft references are provided by the SoftReference class, weak references by the WeakReference class, and phantom references by PhantomReference.

Soft references act like a data cache. When system memory is low, the garbage collector can arbitrarily free an object whose only reference is a soft reference. In other words, if there are no strong references to an object, that object is a candidate for release. The garbage collector is required to release any soft references before throwing an OutOfMemoryException.

Weak references are weaker than soft references. If the only references to an object are weak references, the garbage collector can reclaim the memory used by an object at any time. There is no requirement for a low memory situation. Typically, memory used by the object is reclaimed in the next pass of the garbage collector.

Phantom references relate to cleanup tasks. They offer a notification immediately before the garbage collector performs the finalization process and frees an object. Consider it a way to do cleanup tasks within an object.

Saturday, 12 December 2009

Object references in java


Those readers familiar with C/C++ have probably noticed that object references appear
to be similar to pointers. This suspicion is, essentially, correct. An object reference is
similar to a memory pointer. The main difference—and the key to Java’s safety—is that
you cannot manipulate references as you can actual pointers. Thus, you cannot cause an
object reference to point to an arbitrary memory location or manipulate it like an integer.



The new operator dynamically allocates memory for an object. It has
this general form:
class-var = new classname( );
Here, class-var is a variable of the class type being created. The classname is the name of
the class that is being instantiated. The class name followed by parentheses specifies the
constructor for the class.




Assigning Object Reference Variables

Box b1 = new Box();
Box b2 = b1;



b1 and b2 will

both refer to the same object.







Box b1 = new Box();
Box b2 = b1;
// ...
b1 = null;
Here, b1 has been set to null, but b2 still points to the original object.
Note : When you assign one object reference variable to another object reference variable, you
are not creating a copy of the object, you are only making a copy of the reference.

this - same as cpp



Garbage Collection
Since objects are dynamically allocated by using the new operator, you might be
wondering how such objects are destroyed and their memory released for later
reallocation. In some languages, such as C++, dynamically allocated objects must
be manually released by use of a delete operator. Java takes a different approach; it
handles deallocation for you automatically. The technique that accomplishes this is
called garbage collection. It works like this: when no references to an object exist, that
object is assumed to be no longer needed, and the memory occupied by the object can
be reclaimed. There is no explicit need to destroy objects as in C++. Garbage collection
only occurs sporadically (if at all) during the execution of your program. It will not
occur simply because one or more objects exist that are no longer used. Furthermore,
different Java run-time implementations will take varying approaches to garbage
collection, but for the most part, you should not have to think about it while writing
your programs.







The finalize( ) Method
Sometimes an object will need to perform some action when it is destroyed. For
example, if an object is holding some non-Java resource such as a file handle or
window character font, then you might want to make sure these resources are freed
before an object is destroyed. To handle such situations, Java provides a mechanism

called finalization. By using finalization, you can define specific actions that will occur
when an object is just about to be reclaimed by the garbage collector.

To add a finalizer to a class, you simply define the finalize( ) method. The Java run
time calls that method whenever it is about to recycle an object of that class. Inside the
finalize( ) method you will specify those actions that must be performed before an
object is destroyed. The garbage collector runs periodically, checking for objects that
are no longer referenced by any running state or indirectly through other referenced
objects. Right before an asset is freed, the Java run time calls the finalize( ) method on
the object.
The finalize( ) method has this general form:
protected void finalize( )
{
// finalization code here
}
Here, the keyword protected is a specifier that prevents access to finalize( ) by code
defined outside its class. This and the other access specifiers are explained in Chapter 7.
It is important to understand that finalize( ) is only called just prior to garbage
collection. It is not called when an object goes out-of-scope, for example. This means
that you cannot know when—or even if—finalize( ) will be executed. Therefore, your
program should provide other means of releasing system resources, etc., used by the
object. It must not rely on finalize( ) for normal program operation.
If you are familiar with C++, then you know that C++ allows you to define a destructor
for a class, which is called when an object goes out-of-scope. Java does not support this
idea or provide for destructors. The finalize( ) method only approximates the function
of a destructor. As you get more experienced with Java, you will see that the need for
destructor functions is minimal because of Java’s garbage collection subsystem.