...
Wiki Markup |
---|
While these examples may not model production scenarios, it is not uncommon to have _obsolete references_ when dealing with data structures such as hash tables that contain many large-sized records. It is prudent to assign {{null}} to array-like custom data structures, however, doing so with individual objects or local variables gives no specific advantage. The garbage collector is sufficiently equipped to handle these cases. \[[Commes 07|AA. Java References#Commes 07]\] |
Noncompliant Code Example
A common variant of the aforementioned noncompliant code is the unintentional retention of objects while using a Map
or a similar Collections
object. In this example, a server maintains temporary metadata about all secure connections it commits to. Although the metadata is designed to be transient by nature, it persists even after the particular socket is closed. Unless some notification logic is installed, it is impossible to determine the best time to eliminate the object reference. Likewise, nulling out original objects or referents (Socket connections) by itself, proves to be unwieldy.
Code Block | ||
---|---|---|
| ||
class HashMemLeak {
private Map<SSLSocket, InetAddress> m = Collections.synchronizedMap(new HashMap<SSLSocket, InetAddress>());
public void storeTempConnection(SSLSocket sock, InetAddress ip) {
m.put(sock,ip);
}
public void removeTempConnection(SSLSocket sock) {
m.remove(sock);
}
}
|
Compliant Solution
Wiki Markup |
---|
This compliant solution uses _weak references_ to ameliorate the issue. Strong references typically used in code, do not allow the garbage collector to reclaim the objects that are stored compositely, such as in a {{Map}}. According to \[[API 06|AA. Java References#API 06]\], weak reference objects: |
Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed.
A referent is the object that is being referred to. As soon as any strong references to the object are found to have phased out, the garbage collector reclaims the referent. With WeakHashMap
, the map's key is weakly referred to and thus determines whether the corresponding referents are ready to be collected.
Code Block | ||
---|---|---|
| ||
// ...
private Map<SSLSocket, InetAddress> m = Collections.synchronizedMap(new WeakHashMap<SSLSocket, InetAddress>());
// ...
|
Wiki Markup |
---|
It is not enough to facilitate the collection of unneeded objects with weak references. It is critical to prune the data structure so that more entries can be accommodated in the newly created space. This can be achieved by calling the {{get()}} method of {{WeakHashMap}} and removing the entry that corresponds to the {{null}} return value (polling). A more efficient method is to use a reference queue. \[[Goetz 05b|AA. Java References#Goetz 05b]\] |
If the referent is assigned the value null
, it will eventually be garbage collected. However, the hashmap will continue to strongly reference the WeakReference
object and the corresponding value (for each entry in the hashmap). As soon as the GC clears the reference (which referred to the referent), it adds the corresponding WeakReference
object to the reference queue. It remains there unless some operation is performed on the queue (such as a put()
or remove()
). After such an operation, the WeakReference
object in the hashmap is also collected. Alternatively, this two-step procedure can be carried out manually by using the following code:
Code Block | ||
---|---|---|
| ||
ReferenceQueue queue = new ReferenceQueue();
WeakReference wr = new WeakReference(key, queue); // two-arg constructor, key = 'sock'
hashmap.put(wr, value);
while ((wr = (WeakReference) queue.poll()) != null) {
hashmap.remove(wr); // removes the WeakReference object and the value (not the referent)
}
|
Note that the two-argument constructor of WeakReference
takes a Queue
argument and has to be used in order to perform direct queue processing.
It is also permissible to use soft references since they guarantee that the referent will be reclaimed before an OutOfMemoryError
results but no sooner than the time when memory begins to run out.
Risk Assessment
Memory leaks in Java applications may be exploited, resulting in denial-of-service attacks.
...
Wiki Markup |
---|
\[[API 06|AA. Java References#API 06]\] Class Vector, Class WeakReference \[[Gupta 05|AA. Java References#Gupts 05]\] \[[Bloch 08|AA. Java References#Bloch 08]\] Item 6: Eliminate obsolete object references \[[Commes 07|AA. Java References#Commes 07]\] Memory Leak Avoidance \[[Goetz 05|AA. Java References#Goetz 05]\] Lapsed listeners \[[Goetz 05b|AA. Java References#Goetz 05b]\] "Memory leaks with global Maps" and "Reference queues" \[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 401|http://cwe.mitre.org/data/definitions/401.html] "Failure to Release Memory Before Removing Last Reference (aka 'Memory Leak')" |
...