8

Consider the following scenario: You have a singleton class that represent some sort of data provider. This singleton class allocates a lot of memory,and you want it to release it's allocated memory when there is no one using him. Flow:

  1. Class A call getInstance and uses singleton (this is the first time getInstance called and singleton class allocates huge memory chunk)
  2. Class B call getInstance and uses singleton
  3. Class A and class B "dies" (no one using singleton now)
  4. Program still running but singleton's memory is not released.

How do you suggest implementing singleton that at stage 3 (class A and B "dies") will free the memory (I know that java uses garbage collection but still lets say I want the following memory = null).

PS I don't want to force each class that uses the singleton call release on singleton whenever it stops using it. I want the singleton to handle "releasing" memory by himself.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
JobNick
  • 473
  • 1
  • 6
  • 18

2 Answers2

7

What you can do is

  • only create the singleton the first time it is asked for.
  • store it in a WeakReference. This will only stay alive after a GC if it is still has a "strong" reference elsewhere.

If the WeakReference.get() is null this means it was collected because no-one was using it strongly, another weak reference doesn't count. If it is needed again you need to recreate it and the WeakReference.

Like this,

public enum SingletonHolder{; // no instances

    private static WeakReference<MyType> ref = null;

    public static synchronized MyType getInstance() {
         MyType type = ref == null ? null : ref.get();
         if (type == null)
             ref = new WeakReference<MyType>(type = new MyType());
         return type;
    }
}

BTW This assumes the instances which need this instance retains a reference to it. This is how the weak reference "knows" it is still needed.

BTW2 You don't need synchronized if it is single threaded but it should be harmless.

This means that you should call this method only when a new instance needs it for the first time, not every time and making it more performant shouldn't make much difference e.g. double checking just complicates it.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Hey Peter, Yes I was assuming the other classes that uses the singleton have reference to singleton class. I'm coming from C++ world so lets say when call A get collected by GC would it count that he has no more reference to singleton class or class A should specifically call: singleton = null ? – JobNick Dec 19 '13 at 08:51
  • @JobNick It should do this only if A no longer needs the Singleton but you don't want it to be collected. If you expect instance A to be collected as it has been discarded, you don't need to do this. – Peter Lawrey Dec 19 '13 at 08:56
  • Lets say that GC collected class A that has reference to Singleton object and at some point of time GC decides to collect the Singleton. Who will make the assignment: ref = null or make ref.get() return null So the next time someone want to use the singleton again after is was collected it will be reallocated ? – JobNick Dec 19 '13 at 09:10
1

The use of the Design pattern: "Singleton" is very common and the common implementation is using a static reference.

The problem with this implementation is that many times it leaves floating garbage that is not in use.

For example: A singleton that holds a DB connection pool that is only needed by the application at the start up for confing loading.

Therefor a better solution is an extension to the Singleton design pattern called WeakSingleton.

This pattern does the expected, when all other references to the original instance have expired the instance is cleaned.

An implemenation to this pattern in java is very simple and can be based on WeakReferences.

E.g. Code:

public class WeakSingleton{

static private WeakReference singleton; // instance

public WeakSingleton getInstance(){

  WeakSingleton m = (WeakSingleton)singleton.get();

  if( m != null)

     return m;

  synchronized (WeakSingleton.class){

     m = (WeakSingleton)singleton.get();

     if( m != null)

    return m;       

    m = new WeakSingleton(); // creates new instnace 

    singleton = new WeakReference(m);

  } 

  return m;

 }

}
Prashant Shilimkar
  • 8,402
  • 13
  • 54
  • 89