Think to this example. We need to keep references to some objects currently available in an application and associate to each of them some specific information. A map looks a natural container, but there is a problem: when we should remove a record from it?
When the object is not used anymore, one would say. But we are using Java, no destructor available.
We need a more creative solution, as for instance weak references. In this specific case we have even a better solution, WeakHashMap, a HashMap variation, seems exactly what we are looking for.
An example should make clear what a Java weak reference is, and how to use it:
String strong = new String("Weak"); // 1 WeakReference<String> wa = new WeakReference<String>(strong); // 2 System.out.println("Setup: " + strong); strong = null; // 3 int[][] ia = new int[10][]; // 4 for(int i = 0; i < 10; ++i) { if(wa.get() == null) { // 5 System.out.println("Removed"); return; } System.out.println(i + "] looping on " + wa.get()); // 6 ia[i] = new int[150000]; // 7 } System.out.println("Not removed!?"); // 81. A "normal" reference to an object, is what in this context is usually called a "strong" reference. The garbage collector won't consider for destruction an object till it has at least one strong reference.
2. In this way we create a weak reference. It is not strong enough to save it from destruction by gc, but still provide a way to access the underlying object.
3. Setting a strong reference to null, we remove the connection between it and its original target. Now there is just a weak reference to our String object. Its life is in a serious danger, the garbage collector could decide to destroy it whenever it thinks it is the right moment.
4. The programmer can force the garbage collector the do its job, but I felt it was more interesting allocating some memory and let the JVM decide when to start to collect the garbage.
5. The WeakReference.get() method returns null when the referenced object has been deleted by gc.
6. Theoretically, gc could be called after (5) and before (6), so we could get and print "null" from our WeakReference. But do not expect to see this behavior.
7. The application claims for more memory, increasing the chance that the garbage collector would be called.
8. If you reach this line, the garbage collector has not be called when running the above for loop. Try to increase the quantity of memory claimed on (7).
Instead of using explicitly WeakReference, we could modify the above code and use WeakHashMap:
String key = new String("Key"); // 1 String val = new String("Weak hash map"); // 2 WeakHashMap<String, String> whm = new WeakHashMap<String, String>(); // 3 whm.put(key, val); System.out.println("Setup: " + whm.get("Key")); key = null; // 4 int[][] ia = new int[10][]; for(int i = 0; i < 10; ++i) { String stillThere = whm.get("Key"); // 5 if(stillThere == null) { System.out.println("Removed"); return; } System.out.println(i + "] looping on " + whm.get("Key")); ia[i] = new int[150000]; } System.out.println("Not removed!?");1. In a real case we usually have some more complex object instead a simple String, but for an example it would suffice.
2. Extra information related to the original object.
3. Our weak map where we store the original object as a key and the extra info as value.
4. The key variable does not refer anymore to the original String object. If we used an HashMap, we would still have there a strong reference to it, but we are using WeakHashMap that keeps just a weak reference to its keys.
5. If we used an HashMap, there wouldn't be much sense of looping in this way on get(), it would always return the same value. But here we are using a WeakHashMap, and this means that when the garbage collector is called, all the weak references to the removed object are marked as invalid (null).
No comments:
Post a Comment