I’ve had some issues with DCAF in recent times. The main issue is the DataChangeManager and its in-ability to release locks on elements that are no-longer used inside the application.
Let me take a step back. In DCAF there is a DataChangeManager. This is a singleton that you can register with to receive notifications of changes to a specific class or instance of a BaseBO.
Now in some applications an instance of a BaseBO registers itself as a listener to itself.. Why would u do this? I hear you ask.. In a distributed system where there are multiple VM’s modifying similar data, its useful to be notified of these changes and reload the data accordingly. In conjunction with a DataChangedTransport using something like JMS this is a simple solution.
So now you know the situation, what is the issue. The problem is that the DataChangeManager has a fixed reference to the BO, and if that BO is no longer used by the application the Garbage collector should release it. But as the DataChangeManager is static, and has a reference to this BO the GC is still considers the element reference, even tho technically it isn’t going to be used by the application again. So we get a memory leak.
For a webapp I was working on, we had the User entity listening to itself for changes, and the entity was in a HttpSession. So while the session was active, the User was valid and being used within the application. Changes on a remote VM were propagated across, the User was notified and the contents reloaded. All working nicely.
But then the session is not interacted with for a while (the user closes the browser) and so the session timeout. The servlet container disposes the session and unlinks the User from it, so its no longer used, and we would assume its valid to be GC’d. But in the background the DataChangeManager still retains a reference and so the User lives on.
Without boring you on the details of how the GC works (you can read that anywhere) I’ll just cover the bits relevant here. Basically an object can be GC’d when it is not longer referenced by any valid threads or static instance.
In the previous example, User is referenced via the static DataChangeManager instance and so is not GC’able.
Now to the solution.
What needs to happen is to trick the GC into believing that the reference from the DataChangeManager to the User does not exist, so once all other reference are removed, the User is seen to be GC’able.
This sort of reference is called a “Weak Reference”. From my very quick and limited search through the current Java API’s there is a data structure that stores some data using Weak References, and this is a WeakHashMap.
The keys stored in this map are Weak References, and so not considered by the GC when it is time to work out what object can be GC’d.
So the change, was to update the internals of the DataChangeManager to store the references to the DataChangeListeners in a WeakHashMap instead of a List.
So there, hope that shows off another feature of the Java system that you may not have been too sure about. Please feel free to comment about this approach here, and if you want to try it out for yourself then head over to the development site to pickup a version of DCAF . These changes will be in the 1.2 release of DCAF to be released in the next week or so.