Weak/Soft references?

T

Tegiri Nenashi

I'm not sure I ever saw a convincing example. Let's consider the two
frequented in the literature.

1. HashMap (why not other collection?). I understand that if a
reference to HashMap is still reachable, the whole HashMap and their
references would be reachable, if the reference to HashMap is gone,
the referred objects (keys and values) would decrement their counts
(although counts don't really matter in mark-and-sweep method) . If a
key and a value is not reference anywhere else, then key is supposed
to be marked as garbaged collected. Finally, with the key holding no
references, it is value that is marked to be garbage collected as
well.

2. Listeners. Let's assume a button widget declares a click listener.
So we have a circular reference, and both objects would be garbage
collected when no longer referenced without a problem.

The problem I can imagine is crossing programming environment
boundaries with native calls, but I fail to see this idea supported
anywhere in the literature.

Am I missing something obvious? (Except the idea of a reference that
not guaranteed to be valid at any time being a very insult to common
sense in programming?)
 
J

Joshua Cranmer

Tegiri said:
I'm not sure I ever saw a convincing example. Let's consider the two
frequented in the literature.

I'm still not sure when one would use WeakReferences, but SoftReferences
have good uses.
Am I missing something obvious? (Except the idea of a reference that
not guaranteed to be valid at any time being a very insult to common
sense in programming?)

The most common example, which you seem to have missed is caching, which
is what SoftReferences are used for. The idea is that you want to keep
something in memory for time performance reasons, but, if memory gets
low, you don't actually need it in memory. The solution is a
SoftReference: it hangs around until the memory starts getting low.
 
J

jolz

I'm still not sure when one would use WeakReferences

I'v never had to use myself, but there was exactly one time when I was
really surprised that library I'm using does't use WeakHashMap. The
problem was with log4j - I was getting logger with name corresponding to
my task, and there were lots of differently named tasks. There was no
returnLogger() method, so after tasks were finished, logger's memory was
never reclaimed. Even with returnLogger() or similar method it's simply
more convenient to let WeakHashMap remember about releasing memory.
 
T

Tegiri Nenashi

I'm still not sure when one would use WeakReferences, but SoftReferences
have good uses.


The most common example, which you seem to have missed is caching, which
is what SoftReferences are used for. The idea is that you want to keep
something in memory for time performance reasons, but, if memory gets
low, you don't actually need it in memory. The solution is a
SoftReference: it hangs around until the memory starts getting low.

I admit I overlooked caching because I never if ever used it. Sure I
use some auxiliary structures that speed up processing, but data there
never expire.

OK, here is one more idea I don't understand. Suppose we have a global
map that caches up some things and which one can grow to overwhelm the
available memory. Now wouldn't changing value references to the soft
ones is such a good idea? Consider java.lang.ref.Reference -- a base
class for SoftReference. I counted 5 data members in it. Therefore,
redesigning a map with soft references would blow up the memory, the
effect being more significant for maps containing simple key/value
pairs. Quite odd isn't it solving memory problem by demanding more
memory?-)
 
T

Tom Anderson

OK, here is one more idea I don't understand. Suppose we have a global
map that caches up some things and which one can grow to overwhelm the
available memory. Now wouldn't changing value references to the soft
ones is such a good idea? Consider java.lang.ref.Reference -- a base
class for SoftReference. I counted 5 data members in it. Therefore,
redesigning a map with soft references would blow up the memory, the
effect being more significant for maps containing simple key/value
pairs. Quite odd isn't it solving memory problem by demanding more
memory?-)

You're quite right that using SoftReferences will increase the amount of
memory used to store a given number of objects. But in return, you get the
ability to automatically discard objects when memory is in short supply.
That may be a useful tradeoff.

I would hesitate to use SoftReferences for any object that's about the
same size as the SoftReference itself. I think they're more useful for
large objects, for example parsed XML documents or images. There, a
handful of extra words to buy easier memory management is a good tradeoff.

tom
 
J

Joshua Cranmer

Tegiri said:
OK, here is one more idea I don't understand. Suppose we have a global
map that caches up some things and which one can grow to overwhelm the
available memory. Now wouldn't changing value references to the soft
ones is such a good idea? Consider java.lang.ref.Reference -- a base
class for SoftReference. I counted 5 data members in it. Therefore,
redesigning a map with soft references would blow up the memory, the
effect being more significant for maps containing simple key/value
pairs. Quite odd isn't it solving memory problem by demanding more
memory?-)

The memory overhead of soft, weak, or phantom references is on the order
of bytes. Caches will most likely hold objects consuming hundreds of
kilobytes or more.
 
T

Tegiri Nenashi

You're quite right that using SoftReferences will increase the amount of
memory used to store a given number of objects. But in return, you get the
ability to automatically discard objects when memory is in short supply.
That may be a useful tradeoff.

I would hesitate to use SoftReferences for any object that's about the
same size as the SoftReference itself. I think they're more useful for
large objects, for example parsed XML documents or images. There, a
handful of extra words to buy easier memory management is a good tradeoff.

Why not much simpler solution: a listener on low memory event that
would just clean up all the cache?
 
T

Tegiri Nenashi

The memory overhead of soft, weak, or phantom references is on the order
of bytes. Caches will most likely hold objects consuming hundreds of
kilobytes or more.

To repeat, why not sweep up everything from the cache, triggered by
low memory event? Or you imply that fancy references can be tuned to
provide a specific policy to my cache (e.g. purge 90% of LRU stuff)?
 
T

Tegiri Nenashi

I'v never had to use myself, but there was exactly one time when I was
really surprised that library I'm using does't use WeakHashMap.

How does WeakHashMap is supposed to work? According to javadoc

* An entry in a <tt>WeakHashMap</tt> will automatically be removed
when
* its key is no longer in ordinary use...

My estimate is that more than half of the Map usages are with the
String keys. Now what does it mean the string being no longer in
ordinary use, does it mean nobody refers to literal "abc" anymore so
that the <"abc",...> pair can be removed from the hash? What is the
point to keep the hash map entry if my code still holds reference to
the key?
 
J

Joshua Cranmer

Tegiri said:
To repeat, why not sweep up everything from the cache, triggered by
low memory event? Or you imply that fancy references can be tuned to
provide a specific policy to my cache (e.g. purge 90% of LRU stuff)?

First off, I believe SoftReference has been available since the first
version of Java, notably before Java gained the ability to notify you on
low memory.

Secondly, the low memory notification event comes with this warning:
The memory usage monitoring mechanism is intended for load-balancing or
workload distribution use. For example, an application would stop
receiving any new workload when its memory usage exceeds a certain
threshold. It is not intended for an application to detect and recover
from a low memory condition.

Reasoning why becomes quickly evident:
There is no guarantee about when the MemoryMXBean will emit a threshold
notification and when the notification will be delivered.

Finally, one will generally find that the garbage collector is smarter
about memory collection than you are. Leaving it to the garbage
collector to decide when the SoftReference is taking up too much memory
is probably better than leaving it to you, especially because the
garbage collector has inside knowledge.

So, in short, relying on low memory notifications forces you to rely on
newer versions, is flaky at best since it relies on notifications
happening at ill-defined moments, and assumes that you really know
better than the GC.
 
T

Tegiri Nenashi

First off, I believe SoftReference has been available since the first
version of Java, notably before Java gained the ability to notify you on
low memory.

What this point is supposed to demonstrate? How immature Java
designers are?
Secondly, the low memory notification event comes with this warning:
The memory usage monitoring mechanism is intended for load-balancing or
workload distribution use. For example, an application would stop
receiving any new workload when its memory usage exceeds a certain
threshold. It is not intended for an application to detect and recover
from a low memory condition.

Well, I refuse possibly to believe that it is impossible to design a
modestly reliable system of low memory notification.
Reasoning why becomes quickly evident:
There is no guarantee about when the MemoryMXBean will emit a threshold
notification and when the notification will be delivered.

You have to realize that memory limitation is a physical
implementation artifact, and there is nothing fundamental about it.
Therefore, there is little point making guarantees and inventing
arbitrary constraints on how this event is emitted or delivered.
Finally, one will generally find that the garbage collector is smarter
about memory collection than you are. Leaving it to the garbage
collector to decide when the SoftReference is taking up too much memory
is probably better than leaving it to you, especially because the
garbage collector has inside knowledge.

So? I'm impressed with ingenuity and clarity of mark-and-sweep based
GC. Ditto for the streamlined reference design (compared to the
pointer/reference C++ mess). And now you come back and tell me that we
need more kinds of those pointer thingies?
So, in short, relying on low memory notifications forces you to rely on
newer versions, is flaky at best since it relies on notifications
happening at ill-defined moments, and assumes that you really know
better than the GC.

Well, as someone eloquently put it: "There is no dumber thing than a
smart pointer". This whole fancy references endeavor made me
appreciate it a little more.
 
E

EJP

Joshua said:
First off, I believe SoftReference has been available since the first
version of Java, notably before Java gained the ability to notify you on
low memory.

@since 1.2 actually, but that's sufficiently long ago now ;-)
 
M

Mike Schilling

Joshua said:
I'm still not sure when one would use WeakReferences, but
SoftReferences have good uses.

Here's a simple case for a WeakReference:

G is a GUI widget that displays the state of some object O. In order
to stay up-to-date, G subscribes to events triggered when O changes.
Without WeakReferences, this means that O has a hard link to G, tying
G's lifetime to O's. Since the window containing G should be free to
go away and be cleaned up, this is unfortunate. There are two ways to
improve this:

1. G can be careful to unsubscribing when its parent window exits.
2. G can subscribe via a WeakReference to itself.

2 involves less bookkeeping, and so is more robust. This isn't a
kludge, really. If G is interested in O's state, that should mean
that G refers to O. The fact that O winds up referring to G is purely
implementation. That we can implement it such that O will not refer
to G is a good thing.
 
M

Mike Schilling

Tegiri said:
I'm not sure I ever saw a convincing example. Let's consider the two
frequented in the literature.

1. HashMap (why not other collection?). I understand that if a
reference to HashMap is still reachable, the whole HashMap and their
references would be reachable, if the reference to HashMap is gone,
the referred objects (keys and values) would decrement their counts
(although counts don't really matter in mark-and-sweep method) . If
a
key and a value is not reference anywhere else, then key is supposed
to be marked as garbaged collected. Finally, with the key holding no
references, it is value that is marked to be garbage collected as
well.

You do realize that the key is also referenced by the hash map
internals (to be specific, the entry that contains the key is in some
hash chain.) .Absent some mechanism like weak references, the key
can't be collection unless it's explicitly removed from the map.
 
T

Tegiri Nenashi

You do realize that the key is also referenced by the hash map
internals (to be specific, the entry that contains the key is in some
hash chain.)  .Absent some mechanism like weak references, the key
can't be collection unless it's explicitly removed from the map.

Is "hash internals" some global structure? Otherwise, I don't see why
a whole subgraph of HashMap references -- no matter how messy it is --
won't be marked for deletion when the link to the root is deleted.
 
T

Tegiri Nenashi

You do realize that the key is also referenced by the hash map
internals (to be specific, the entry that contains the key is in some
hash chain.)  .Absent some mechanism like weak references, the key
can't be collection unless it's explicitly removed from the map.

Ok, let's be more specific.

class HashMap {
Entry[] table;
...
}

No problem here, I assume if there is no references to HashMap all the
rederences to Entry would be marked for deletion.

class Entry<K,V> {
K key;
V value;
Entry<K,V> next;
}

Next if the Entry object is marked for deletion, then key, value, and
the next entry in the chain are maked as well.

So, there is nothing specific about the key at all!
 
M

Mike Schilling

Tegiri said:
Is "hash internals" some global structure?

The internals of the HashMap implementation
Otherwise, I don't see why
a whole subgraph of HashMap references -- no matter how messy it
is --
won't be marked for deletion when the link to the root is deleted.

Read up a bit on how HashMaps are implemented and you'll begin to
understand it. If you can design an alternate implementation that
allows the sort of collection you just described, I'd be very
interested in seeing it.
 
T

Tegiri Nenashi

Here's a simple case for a WeakReference:

G is a GUI widget that displays the state of some object O.  In order
to stay up-to-date, G subscribes to events triggered when O changes.
Without WeakReferences, this means that O has a hard link to G, tying
G's lifetime to O's.  Since the window containing G should be free to
go away and be cleaned up, this is unfortunate.  There are two ways to
improve this:

1. G can be careful to unsubscribing when its parent window exits.
2. G can subscribe via a WeakReference to itself.

2 involves less bookkeeping, and so is more robust.  This isn't a
kludge, really.  If G is interested in O's state, that should mean
that G refers to O.  The fact that O winds up referring to G is purely
implementation.  That we can implement it such that O will not refer
to G is a good thing.

To quote another guy, who is mathematician, computer buffs like to
complicate everything. Let see what is important in your example. You
have a parent widget, child widget and an external data object that
child references. No matter how complicated references subgraph for
the system of all the three objects in our picture are, this whole
hairball of references would be disconnected from the outside world as
soon as parent goes away, no?
 
J

jolz

My estimate is that more than half of the Map usages are with the
String keys. Now what does it mean the string being no longer in
ordinary use, does it mean nobody refers to literal "abc" anymore so
that the <"abc",...> pair can be removed from the hash?

String is almost like any other object. If there is no reference to the
object, it is removed. For example:
WeakHashMap<String, String> m = new WeakHashMap<String, String>();
m.put(new String("1"), "1");
while (true) {
System.gc();
if (m.size() == 0) {
break;
}
}
What is the
point to keep the hash map entry if my code still holds reference to
the key?

If yor code still holds the reference, object isn't weakly reachable and
won't be removed from WeakHashMap. You may remove it manually if you want.
 
J

Joshua Cranmer

Tegiri said:
To quote another guy, who is mathematician, computer buffs like to
complicate everything. Let see what is important in your example. You
have a parent widget, child widget and an external data object that
child references. No matter how complicated references subgraph for
the system of all the three objects in our picture are, this whole
hairball of references would be disconnected from the outside world as
soon as parent goes away, no?

No. The graph looks like this:

Window <-> Widget <- Data Manager

The implication is that the Data Manager is going to be around for a
long time; let's say it was a TCP connection manager and our widget is
popping up in a network monitor window. Obviously, you'd want the Window
and Widget to be reclaimable as soon as you close the window, but the
Data Manager will refuse to let them be reclaimed since its held to for
the entirety of the application.

If you open up a lot of windows... MEMORY LEAK!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top