Available CategoriesAdobeMacromediaProgrammingSQLServer AdministrationNetworkingMicrosoft ProductsMac OSLinux systemsMobile devicesXMLCertificationMiscAvailable Tutorials.NET Framework Essentials.NET Programming securityC# In A Nutshell TutorialProgramming C.SharpMastering Visual Studio .NETASP.NETWeb Solutions based on ASP.NET and ADO.NETJava data objectsJava extreme programmingJava performance tuningJava development on pda's. Building applications for pocket pc and palm devicesJavaScript and DHTMLLearning UMLUMLLearning XMLCocoaProgramming CppPerl objects, references and modulesPerl tutorialPython tutorialPython. Text processingPocket pc network programmingPHP & MySQL. Building web database applicationsPHP & MySQL. Programming for beginnersPHP, MySQL and Apache in 24 hoursSoftware architecture in practiceSoftware engineering and computer gamesBuilding Solutions With the Microsoft .NET Compact FrameworkProgramming Microsoft Visual C# 2005ActionscriptMastering Delphi 7Ado.netPractical mod_perlPerl for bioinformaticsWeb ServicesPrinciples of Secure CodingC/C++ Secure ProgrammingASP.NET AJAXVisual C#Borland C++ Builder 6 Developer's Guide |
4.3 Reference Objects
Reference ref = new WeakReference(someObject);
//ref.get( ) is someObject at the moment
//Now do something that creates lots of objects, making
//the garbage collector try to find more memory space
doSomething( );
//now test if ref is null
if (ref.get( ) = = null)
System.out.println("The garbage collector deleted my ref");
else
System.out.println("ref object is still here");
Note that the referent can be garbage-collected at any time, as long as there are no other strong references referring to it. (In the example, ref.get( ) can become null only if there are no other non-Reference objects referring to someObject.) The advantage of References is that you can use
them to hang onto objects that you want to reuse but are not needed
immediately. If memory space gets too low, those objects not
currently being used are automatically reclaimed by the garbage
collector. This means that you subsequently need to create objects
instead of reusing them, but that is preferable to having the program
crash from lack of memory. (To delete the reference object itself
when the referent is nulled, you need to create the reference with a
ReferenceQueue instance. When the reference object
is cleared, it is added to the
4.3.1 Reference TypesThere are three Reference types in Java 2. WeakReferences and SoftReferences differ essentially in the order in which the garbage collector clears them. Simplistically, the garbage collector does not clear SoftReference objects until all WeakReferences have been cleared. PhantomReferences (not addressed here) are not cleared automatically by the garbage collector and are intended for use in a different way. Sun's documentation suggests that WeakReferences could be used for canonical tables, whereas SoftReferences would be more useful for caches. In the previous edition, I suggested the converse, giving the rationale that caches take up more space and so should be the first to be reclaimed. But after a number of discussions, I have come to realize that both suggestions are simply misleading. What we have are two reference types, one of which is likely to be reclaimed before the other. So you should use both types of Reference objects in a priority system, using the SoftReference objects to hold higher-priority elements so that they are cleared later than low-priority elements. For both caches and canonical tables, priority would probably be best assigned according to how expensive it is to recreate the object. In fact, you can also add PhantomReferences as a third, even higher-priority element. PhantomReferences would be cleared last of all. 4.3.2 SoftReference FlushingPrior to Version 1.3.1, SoftReferences and WeakReferences were treated fairly similarly by the VM, simply being cleared whenever they were no longer strongly (and weakly) reachable, with only a slight ordering difference. However, from 1.3.1 on, the Sun VM started treating SoftReferences differently. Now, SoftReferences remain alive for some time after the last time they were referenced. The default length of time value is one second of lifetime per free megabyte in the heap. This provides more of a differentiation between SoftReference and WeakReference behavior. The initial time-to-live values for SoftReferences can be altered using the -XX:SoftRefLRUPolicyMSPerMB flag, which specifies the lifetime per free megabyte in the heap, in milliseconds. For example, to change the value to 3 seconds per free heap megabyte, you would use: % java -XX:SoftRefLRUPolicyMSPerMB=3000 ... The server mode VM and client mode VM use slightly different methods to calculate the free megabytes in the heap. The server mode VM assumes that the heap can expand to the -Xmx value and uses that as the full heap size to calculate the available free space. The client mode VM simply uses the current heap size, deriving the actual free space in the current heap. This means that the server VM has an increased likelihood of actually growing the heap space rather than clearing SoftReferences, even where there are SoftReferences that could otherwise be reclaimed. This behavior is not part of any specification, so it could change in a future version. But it is likely that some difference in behavior between WeakReferences and SoftReferences will remain, with SoftReferences being longer lived. 4.3.3 The WeakHashMap ClassTo complete our picture on references and how they work, we'll look in detail at the implementation and performance effects of the WeakHashMap class. WeakHashMap is a type of Map that differs from other Maps in more than just having a different implementation. WeakHashMap uses weak references to hold its keys, making it one of the few classes able to respond to the fluctuating memory requirements of the JVM. This can make WeakHashMap unpredictable at times, unless you know exactly what you are doing with it. 4.3.3.1 How WeakHashMap worksThe keys in a WeakHashMap are WeakReference objects. The object passed as the key to a WeakHashMap is stored as the referent of the WeakReference object, and the value is the standard Map value. (The object returned by calling Reference.get( ) is termed the referent of the Reference object.) A comparison with HashMap can help:
The 1.2 and 1.3 versions of the WeakHashMap implementation wrap a HashMap for its underlying Map implementation and wrap keys with WeakReferences (actually a WeakReference subclass) before putting the keys into the underlying HashMap. The 1.4 version implements a hash table directly in the class, for improved performance. The WeakHashMap uses its own ReferenceQueue object so that it is notified of keys that have been garbage-collected, thus allowing the timely removal of the WeakReference objects and the corresponding values. The queue is checked whenever the Map is altered. In the 1.4 version, the queue is also checked whenever any key is accessed from the WeakHashMap. If you have not worked with Reference objects and ReferenceQueues before, this can be a little confusing, so I'll work through an example. The following example adds a key-value pair to the WeakHashMap, assumes that the key is garbage-collected, and records the subsequent procedure followed by the WeakHashMap:
As you can see, we take each WeakReference out of the queue and remove it from the Map. This also releases the corresponding value object, and both the WeakReference object and the value object can now be garbage-collected if there are no other strong references to them.
4.3.3.2 Some consequences of the WeakHashMap implementation
Unlike many other collections, WeakHashMap cannot maintain a count of elements, as keys can be cleared at any time by the garbage collector without immediately notifying the WeakHashMap. This means that seemingly simple methods such as isEmpty( ) and size( ) have more complicated implementations than for most collections. Specifically, size( ) in the 1.2 and 1.3 implementations actually iterates through the keys, counting those that have not been cleared. Consequently, size( ) is an operation that takes time proportional to the size of the WeakHashMap. In the 1.4 implementation, size( ) processes the reference queue, then returns the current size. Similarly, in the 1.2 and 1.3 implementations, isEmpty( ) iterates through the collection looking for a non-null key. This produces the perverse result that a WeakHashMap that had all its keys cleared and is therefore empty requires more time for isEmpty( ) to return than a similar WeakHashMap that is not empty. In the 1.4 implementation, isEmpty( ) processes the reference queue and returns whether the current size is 0, thus providing a more consistent execution time, although on average the earlier isEmpty( ) implementation would be quicker.
|