Friday, November 5, 2010

Java References

For a long years, I have been working with Java, but now only working with mobile application. It is interesting, but sometime it is within a triangle sided by Performance, Quality and Resource. If we try to improve one then application may hit by other. Not like servers or desktop we can't increase resources as we need in mobile devices.

Lets look at Java References which provides support to reclaim objects when memory demand.

You all know that,
1. Java has garbage collector (GC) which will take care of removing unused objects, so no need handle object removable inside the program.
2. when java trying to create a object, if it can not allocate memory, then it will throw OutofMemoryError.
3. Even if you run a java application just with only one thread. i.e the main thread, there at least two thread will be running, one is the main thread and other one is the GC thread.

To check this out, I wrote a class:

class MyObject{
private int index;
private byte [] bs = new byte[16*1024*1024];
public MyObject(int index) {
super();
System.out.println("creating index="+index);
this.index = index;
}

@Override
protected void finalize() throws Throwable {
System.out.println("finalizing index="+index);
super.finalize();
}
}


When create a MyObject this will allocate 16*1024*1024 (=16Mb) memory. And will print "creating index=*" while creating and "finalizing index=*" while removing from heap.

1. First, lets create a unreachable objects.
private static void unreachable() {
for(int i = 0;i<1000;i++){
new MyObject(i);
}
}


If you run this you will get:
creating index=0
finalizing index=0
creating index=1
finalizing index=1
creating index=2
creating index=3
finalizing index=2
finalizing index=3
...
This means these objects will be removed each next CG thread.

2. Strong References:
private static void stongReference() {
List references = new ArrayList();
for(int i=0;i<1000;i++){
references.add(new MyObject(i));
}
}


creating index=0
creating index=1
creating index=2
creating index=3
creating index=4
creating index=5
creating index=6
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at DemoReferences$MyObject.(DemoReferences.java:12)
at DemoReferences.stongReference(DemoReferences.java:50)
at DemoReferences.main(DemoReferences.java:35)

Yes you will get OutOfMemoryError, because non of the objects can't be collected since all are strong reference.

3. Weak Reference
private static void weakReference() {
List> references = new ArrayList>();
for(int i = 0; i < 1000;i++){
references.add(new WeakReference(new MyObject(i),referenceQueue));
}
}
creating index=0
finalizing index=0
creating index=1
creating index=2
finalizing index=1
creating index=3
finalizing index=2
finalizing index=3
...
This looks same as unreachable objects. But as long as it available by calling WeakReference.get() can get the object back.

4. Soft Reference
private static void softReference() {
List> references = new ArrayList>();
for(int i = 0 ; i < 10000;i++){
references.add(new SoftReference(new MyObject(i),referenceQueue));
}
}


creating index=0
creating index=1
creating index=2
creating index=3
creating index=4
creating index=5
creating index=6
finalizing index=6
finalizing index=5
finalizing index=4
finalizing index=3
finalizing index=2
finalizing index=1
finalizing index=0
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at DemoReferences$MyObject.(DemoReferences.java:12)
at DemoReferences.softReference(DemoReferences.java:64)
at DemoReferences.main(DemoReferences.java:36)

This may looks like Strong Reference, but VM make sure to remove all object before throw OutOfMemoryError. So, the error can be caught and try again.

private static void softReference() {
List> references = new ArrayList>();
for(int i = 0 ; i < 10000;i++){
try{
references.add(new SoftReference(new MyObject(i),referenceQueue));
}catch(OutOfMemoryError error){
System.out.println(error.getMessage());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
references.add(new SoftReference(new MyObject(i),referenceQueue));

}
}
}


creating index=0
creating index=1
creating index=2
creating index=3
creating index=4
creating index=5
creating index=6
finalizing index=6
finalizing index=5
finalizing index=4
finalizing index=3
finalizing index=2
finalizing index=1
finalizing index=0
finalizing index=0
creating index=7
...

Here also SoftReference.get() will give you the object if not removed. In this way we can keep the objects for long time as long as there is a memory demand.
This will be a good approach to create a memory sensitive cache.

4 comments:

Herath Kathir said...

Hi Dicca, This is realy a good approach for handling the memory in mobile devices. Thanks for your your posting and keep doing the good job.

Thanks
Herath

Sudar Nimalan said...

Thanks Herath,
I didn't write too much about each reference, but you can find from those links.

Vel Velauthapillai said...

Good stuff..

Not a Java guy yet.. But wouldn't that WeakHashMap solve this problem? It should act like a memory cache. No?

Sudar Nimalan said...

Thanks for your comments...
Looks WeakHaskMap bit different from References, Let me check this more and write...