{"id":1229,"date":"2011-03-26T11:27:19","date_gmt":"2011-03-26T16:27:19","guid":{"rendered":"http:\/\/unitstep.net\/?p=1229"},"modified":"2017-12-31T17:47:28","modified_gmt":"2017-12-31T22:47:28","slug":"java-weak-references-and-weakhashmap","status":"publish","type":"post","link":"https:\/\/unitstep.net\/blog\/2011\/03\/26\/java-weak-references-and-weakhashmap\/","title":{"rendered":"Java, Weak References and WeakHashMap"},"content":{"rendered":"
Most any Java Developer will be familiar with the concepts of references<\/em>, as in pass-by-reference vs. pass-by-value. (Pointers, now that’s another thing…)<\/p>\n When calling methods, primitive data types are passed by value, while objects and arrays are passed by reference. This means when you call a method with an object as a parameter, you are merely providing that method a way to access\/manipulate the same<\/em> object via a reference; no copy is made. Contrast that with primitives: When calling a method that requires them, a copy of that value is put on the call stack before invoking the method.<\/p>\n In that way, references are somewhat like pointers, though they obviously cannot be manipulated by pointer arithmetic. But what about weak references<\/strong>? What are they, and how do they contrast with strong<\/em> references?<\/p>\n <\/p>\n Based on my experience, the concept of weak references, or more generally reachability, is not one that is well-understood in the Java world. At least I did not have a good grasp of them until stumbling upon some sample code one day. It may be that the need to utilize them is outside the confines of most day-to-day programming tasks, as the concept is fairly low-level. Nonetheless, it’s an important concept to understand.<\/p>\n Basically, Java specifies five levels of reachability for objects that reflect which state the object is in, in relation to being marked as finalizable, being finalized and being reclaimed. They are, in order of strongest-to-weakest:<\/p>\n An object’s normal state, as soon as it has been instantiated and assigned to a variable\/field is strongly reachable<\/em>. Chances are, these are the only types of objects you’ve worked with. We’ll first cover the concept of weakly reachable<\/em> objects, as I believe it provides a good base for understanding the remainder.<\/p>\n Going by the API reference<\/a>, a weakly reachable object is one that can be reached by traversing (i.e. going through) a weak reference. That’s a succinct definition to be sure, but it just raises the next question: What is a weak reference?<\/p>\n Simply put, if an object can only be reached by traversing a weak reference, the garbage collector will not attempt to keep the object in memory any more than it would an object with no references to it<\/strong>, i.e. an object that cannot be accessed. Thus, from the garbage collector’s point-of-view, a weakly-referenced object will eventually be cleaned from memory the same as an object no references to it.<\/p>\n So, if weakly-referenced objects are treated the same as completely non-referenced ones, what is the purpose of the weak reference? A good example is the WeakHashMap<\/a>, a class provided by Java.<\/p>\n The best way to describe a WeakHashMap is one where the entries (key-to-value mappings) will be removed when it is no longer possible to retrieve them from the map. For example, say you’ve added an object to the WeakHashMap using a key k1<\/em>. If you now set k1<\/em> to null, there should be no way to retrieve the object from the map, since you don’t have the key object around any more to call This makes it ideal for use as a cache of sorts. A typical use case is to associate keys with some large objects that take up a lot of memory; with only a weak reference to the keys, when there is no longer any external reference to the keys, the entry for it will be removed, which will also remove the WeakHashMap’s reference to the value objects. This can also make the value objects then eligible for garbage collection, *provided there are no other strong references* to the value objects outside of the map.<\/p>\n Note that for the WeakHashMap to work this way, as it was intended, the key objects must only be considered equal if they are actually the same object – i.e. object identity instead of mere equality. This is the default behaviour for Another point of importance is that An example of String interning:<\/p>\n String objects are interned for performance reasons, so when you are going to create a new String, Java first checks if there is a String in the pool that is “equal” to the one you are creating. If such a String exists, the existing object is just returned instead of having to instantiate a new object. This is possible because Strings in Java are immutable, i.e. operations that appear to modify a String (such as concatenation, The last usage note is that even though the keys are weakly-referenced by WeakHashMap, the values remain strongly-referenced. Thus, you must take care to not use value objects that strongly reference the keys themselves, as if this happens, the keys\/entries will no longer be automatically dropped because a strong reference may always exist to the keys. (This can be avoided by wrapping the value object in a WeakReference<\/a>, so that both keys and values are weakly-referenced when in the WeakHashMap)<\/p>\n Here is a brief, albeit contrived example of In an upcoming article, I plan on covering the other types of references (soft and phantom) as well as the associated Most any Java Developer will be familiar with the concepts of references, as in pass-by-reference vs. pass-by-value. (Pointers, now that’s another thing…) When calling methods, primitive data types are passed by value, while objects and arrays are passed by reference. This means when you call a method with an object as a parameter, you are […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[64,197,137],"tags":[450,382,383],"_links":{"self":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1229"}],"collection":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/comments?post=1229"}],"version-history":[{"count":11,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1229\/revisions"}],"predecessor-version":[{"id":1769,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1229\/revisions\/1769"}],"wp:attachment":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/media?parent=1229"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/categories?post=1229"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/tags?post=1229"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}Weakly understood<\/h2>\n
\n
Cleaning out the trash<\/h2>\n
WeakHashMap<\/h2>\n
get()<\/code> with. This behaviour is possible because WeakHashMap only has weak references to the keys, not strong references like the other Map classes.<\/p>\n
Object.equals()<\/code> and
Object.hashCode()<\/code>, so if these methods have not been overridden, the object is OK to be used as a key in WeakHashMap. Objects like
Integer<\/code> are not suitable for use in WeakHashMap, because it is possible to create two separate (non-identical) objects that are both equal:<\/p>\n
final Integer i1 = new Integer(4);\r\nfinal Integer i2 = new Integer(4);\r\nLOGGER.debug(\"i1.equals(i2): \" + i1.equals(i2)); \/\/ True.\r\nLOGGER.debug(\"i1 == i2: \" + (i1 == i2)); \/\/ False.<\/code><\/pre>\n
String<\/code> is not a suitable key for a WeakHashMap as well. In addition to its overriding of
equals()<\/code> and
hashCode()<\/code>, String objects in Java are also interned (i.e. stored) in a pool by the JVM when created. This means that they may remain strongly referenced even after you have apparently gotten rid of your reference to them. Because of this, entries that you add to a WeakHashMap using String keys may never get dropped, even after you have apparently lost reference to the keys, since the Strings may remain strongly referenced in the string intern pool.<\/p>\n
final String s1 = \"The only thing we have to fear is fear itself.\";\r\nfinal String s2 = \"The only thing we have to fear is fear itself.\";\r\nLOGGER.debug(\"s1.equals(s2): \" + s1.equals(s2)); \/\/ True.\r\nLOGGER.debug(\"s1 == s2: \" + (s1 == s2)); \/\/ May also return true!<\/code><\/pre>\n
toUpperCase()<\/code>, etc.) really return a new String object while preserving the original.<\/p>\n
Example use of WeakHashMap<\/h2>\n
WeakHashMap<\/code> at work:<\/p>\n
\/\/ SampleKey is just an object that holds a single int. (Use instead of\r\n\/\/ Integer, since Integer overrides equals() and hashcode())\r\nSampleKey key = new SampleKey(42);\r\nSampleObject value = new SampleObject(\"Sample Value\");\r\n\r\nfinal WeakHashMap<SampleKey, SampleObject> weakHashMap = new WeakHashMap<SampleKey, SampleObject>();\r\nweakHashMap.put(key, value);\r\n\r\n\/\/ At this point, we still have a strong reference to the key. Thus, even\r\n\/\/ though the key is weakly-referenced by the WeakHashMap, nothing will\r\n\/\/ be automatically removed even if we give a hint to the GC.\r\nSystem.gc();\r\n\r\nLOGGER.debug(weakHashMap.size()); \/\/ Will still be '1'.\r\nLOGGER.debug(weakHashMap.get(key)); \/\/ Will still be 'Sample Value'.\r\n\r\n\/\/ Now, we if set the key to null, the entry in weakHashMap will eventually\r\n\/\/ disappear. Note that the number of times we have to 'kick' the GC\r\n\/\/ before the entry disappears may be different on each run depending\r\n\/\/ on the JVM load, memory usage, etc.\r\n\/\/ This could also allow the SampleObject value to be GC'd, provided there\r\n\/\/ were no other references to it.\r\nkey = null;\r\nvalue = null;\r\nint count = 0;\r\nwhile(0 != weakHashMap.size())\r\n{\r\n ++count;\r\n System.gc();\r\n}\r\nLOGGER.debug(\"Took \" + count + \" calls to System.gc() to result in weakHashMap size of : \" + weakHashMap.size());<\/code><\/pre>\n
Finishing up<\/h2>\n
Reference<\/code> classes in Java. I wanted to keep this post brief so that it provided a basic understanding of the situation.<\/p>\n
Changes\/Fixes<\/h4>\n
\n
WeakHashMap<\/code> as a cache.<\/li>\n<\/ul>\n
References<\/h3>\n
\n