A bit confused with SoftReference - when exactly is it collected?

T

Thomas Kellerer

Hello,

I'm using a SoftReference to a StringBuffer to build up log messages that are
later displayed in a Swing GUI. As this might potentially grow but I don't want
the messages to be causing an OOME (as most of them will be written into the log
file anyway) I am storing the actual StringBuffer in a SoftReference.

My understand was, that a SoftReference will not be collected until the JVM runs
out of memory. But it seems that when I run a lengthy task that does create a
lot of temporary objects, the soft reference is cleared even though the
available memory (max heap) is big enough.

The only explanation I have: the JVM will already collect SoftReferences before
even expanding the current heap (even if way below the -Xmx value), or - even
worse - just at will ;)

Can anybody shed some light on this?

Currently this does not really help me with my problem. Is there anyway to
implement an object that *only* gets collected if the JVM cannot expand the heap
any more (-Xmx reached)?

Regards
Thomas
 
O

Oliver Wong

Thomas Kellerer said:
Hello,

I'm using a SoftReference to a StringBuffer to build up log messages that
are later displayed in a Swing GUI. As this might potentially grow but I
don't want the messages to be causing an OOME (as most of them will be
written into the log file anyway) I am storing the actual StringBuffer in
a SoftReference.

My understand was, that a SoftReference will not be collected until the
JVM runs out of memory. But it seems that when I run a lengthy task that
does create a lot of temporary objects, the soft reference is cleared even
though the available memory (max heap) is big enough.

The only explanation I have: the JVM will already collect SoftReferences
before even expanding the current heap (even if way below the -Xmx value),
or - even worse - just at will ;)

Can anybody shed some light on this?

The javadocs explain exactly what guarantees are and are not made with
regards to SoftReference. As usual for things intimately tied with the
garbage collector, a lot of its behaviour is implementation defined.
Currently this does not really help me with my problem. Is there anyway to
implement an object that *only* gets collected if the JVM cannot expand
the heap any more (-Xmx reached)?

Not to my knowledge. A simple fix for your design might be to strongly
store the last 10 log entries, and then softly store any entries beyond
that, which may or may not get reclaimed by the GC, depending on its mood.

- Oliver
 
T

Thomas Kellerer

Oliver Wong wrote on 13.11.2006 22:25:
The javadocs explain exactly what guarantees are and are not made with
regards to SoftReference. As usual for things intimately tied with the
garbage collector, a lot of its behaviour is implementation defined.
Well the Javadocs says (and that's the reason for my assumptions):

"All soft references to softly-reachable objects are guaranteed to have been
cleared before the virtual machine throws an OutOfMemoryError. Otherwise no
constraints are placed upon the time at which a soft reference will be cleared
or the order in which a set of such references to different objects will be
cleared."

Especially the part about "Otherwise no constraints are placed upon the time",
which sounds to me like "The will *only* be collected to prevent an OOME", which
clearly isn't the case.
A simple fix for your design might be to strongly
store the last 10 log entries, and then softly store any entries beyond
that, which may or may not get reclaimed by the GC, depending on its mood

Yes, I was thinking about that as well...

Thomas
 
T

Thomas Hawtin

Thomas said:
My understand was, that a SoftReference will not be collected until the
JVM runs out of memory. But it seems that when I run a lengthy task that
does create a lot of temporary objects, the soft reference is cleared
even though the available memory (max heap) is big enough.

It is guaranteed that the SoftReference will be cleared in preference to
throwing an OOME. The reverse implication is not true.

Sun's implementation by default clears a SoftReference if after a
collection the number of free megabytes of memory is less that the
number of seconds since the reference was last used. The Server HotSpot
takes into account the maximum memory available (-Xmx), whereas the
Client HotSpot uses the current heap allocation.

Tom Hawtin
 
T

Thomas Kellerer

Thomas Hawtin wrote on 13.11.2006 22:52:
It is guaranteed that the SoftReference will be cleared in preference to
throwing an OOME. The reverse implication is not true.

Sun's implementation by default clears a SoftReference if after a
collection the number of free megabytes of memory is less that the
number of seconds since the reference was last used. The Server HotSpot
takes into account the maximum memory available (-Xmx), whereas the
Client HotSpot uses the current heap allocation.

Thanks for the explanation, especially the difference between client and server VM.

Basically what I expected (and have experienced) I do think the Javadocs are a
bit vague about this (your statement would have helped me a lot in the Javadocs)

Thomas
 
O

Oliver Wong

Thomas Kellerer said:
Oliver Wong wrote on 13.11.2006 22:25:
Well the Javadocs says (and that's the reason for my assumptions):

"All soft references to softly-reachable objects are guaranteed to have
been cleared before the virtual machine throws an OutOfMemoryError.
Otherwise no constraints are placed upon the time at which a soft
reference will be cleared or the order in which a set of such references
to different objects will be cleared."

Especially the part about "Otherwise no constraints are placed upon the
time", which sounds to me like "The will *only* be collected to prevent an
OOME", which clearly isn't the case.

No, "no constraints" means the JVM is allowed to do whatever it wants.
For example, it could ALWAYS clear the SoftReference immediately, so that
the getter always returns null.

- Oliver
 
T

Thomas Kellerer

Sun's implementation by default clears a SoftReference if after a
collection the number of free megabytes of memory is less that the
number of seconds since the reference was last used. The Server HotSpot
takes into account the maximum memory available (-Xmx), whereas the
Client HotSpot uses the current heap allocation.

One thing that strikes me with this implementation: what is the
difference between a WeakReference and a SoftReference then?

I would have expected the described behaviour when using a
WeakReference, but not with a SoftReference

Thomas
 
C

Chris Uppal

Thomas said:
One thing that strikes me with this implementation: what is the
difference between a WeakReference and a SoftReference then?

The difference is to allow the JVM room to be more reluctant to clear a
SoftReference than a WeakReference. Note that word "allow".

I think that in general Oliver's suggestion is the only way to handle this,
assuming that you want to use the weak/soft reference architecture at all. But
I question whether, for this specific application, soft/weak refs are worth the
effort. It would take a fair bit of code without obviously improving the
user-experience (either the user wants that info, in which case you shouldn't
throw it away, or s/he doesn't, in which case why keep it at all?) You could
either write the messages to an ever-growing (temporary?) file, and make the
GUI display that, or put a hard limit on how much "history" was ever going to
be available, and keep that much unconditionally.

-- chris
 
T

Twisted

The reference I've never seen much use for is the PhantomReference.
Even if you put it in a reference queue, by the time you get the phone
call it's gone! I'm not clear where it's useful where a WeakReference
won't do as well.

On another note, I see mention of the "server VM". I'd always gathered
that that is just "what you get when you put -server on the command
line", but putting -server on the command line of any of the HotSpot
VMs I've gotten downloading Sun's JDKs and JREs produces an error
message. Apparently it's actually a separate VM implementation
altogether -- and I have no idea where to find it on Sun's site,
either. It's not obvious where it is, but it apparently has significant
advantages even on the desktop, such as better GC and memory usage,
saner SoftReference behavior, and better HotSpot optimization. (Someone
profiled some FP code for me and found that FP math in a tight loop
runs at C-native speeds with -server but not with a normal Hotspot VM
like what I have after there's been time for the JIT to kick in. A
normal Hotspot VM is never more than about half C-native speeds at FP
math it seems. For scientific applications and simulation work, this is
a big freaking deal.)
 
T

Thomas Kellerer

The difference is to allow the JVM room to be more reluctant to clear a
SoftReference than a WeakReference. Note that word "allow".

I think that in general Oliver's suggestion is the only way to handle this,
assuming that you want to use the weak/soft reference architecture at all. But
I question whether, for this specific application, soft/weak refs are worth the
effort. It would take a fair bit of code without obviously improving the
user-experience (either the user wants that info, in which case you shouldn't
throw it away, or s/he doesn't, in which case why keep it at all?) You could
either write the messages to an ever-growing (temporary?) file, and make the
GUI display that, or put a hard limit on how much "history" was ever going to
be available, and keep that much unconditionally.

As I said, the error messages are also logged into a log file but which
cannot be displayed directly as it contains a lot more information.

My assumption was: the user will more likely trade a successful
completion of the task against losing some informational messages. And
for this the SoftReference sounded nice - keep the stuff in memory until
we run out of memory. Only then the messages are removed.

I guess the approach with the numer of messages is the only sensbile then.

Thanks for all the feedback

Thomas
 
T

Thomas Kellerer

> On another note, I see mention of the "server VM". I'd always gathered
that that is just "what you get when you put -server on the command
line", but putting -server on the command line of any of the HotSpot
VMs I've gotten downloading Sun's JDKs and JREs produces an error
message.

java -server works fine for me. It's even mentioned in the commandline
help if you only type java

Thomas
 
T

Thomas Hawtin

Twisted said:
The reference I've never seen much use for is the PhantomReference.
Even if you put it in a reference queue, by the time you get the phone
call it's gone! I'm not clear where it's useful where a WeakReference
won't do as well.

There's two ways of using References. The most obvious is you read the
reference and check it hasn't gone. The other way is to subclass and
ignore get. The point of subclassing is that when you pick the Reference
off the ReferenceQueue relevant information is available (although not
the actual target object). PhantomReference can be used for cleanup,
much the same as finalisers. Finalisers are, however, easier to write (I
say easier, but to get them correct still isn't easy).
On another note, I see mention of the "server VM". I'd always gathered
that that is just "what you get when you put -server on the command
line", but putting -server on the command line of any of the HotSpot
VMs I've gotten downloading Sun's JDKs and JREs produces an error
message. Apparently it's actually a separate VM implementation
altogether -- and I have no idea where to find it on Sun's site,
either. It's not obvious where it is, but it apparently has significant
advantages even on the desktop, such as better GC and memory usage,
saner SoftReference behavior, and better HotSpot optimization.

Let me guess. You are using Windows. IIRC, the server VM on Windows is
in the JDK but not the JRE. However, you can copy it from the JDK into
the JRE.

There is no AMD64 client VM, but taking the opposite approach from
Windows, if you ask for -d64 -client it silently gives the 64-bit server
VM instead (silently unless you use -showversion, of course).
(Someone
profiled some FP code for me and found that FP math in a tight loop
runs at C-native speeds with -server but not with a normal Hotspot VM
like what I have after there's been time for the JIT to kick in. A
normal Hotspot VM is never more than about half C-native speeds at FP
math it seems. For scientific applications and simulation work, this is
a big freaking deal.)

Yup. Also note trig functions in particular will run faster on non-x86
processors, as the x87 is too imprecise for the Java specification.

Tom Hawtin
 
T

Twisted

Thomas said:
java -server works fine for me. It's even mentioned in the commandline
help if you only type java

Eh. Well, I changed the JRE launch options under Eclipse to add
"-server" one time and all attempts to launch something then failed
with an error message implying that the switch was invalid for the JVM
I was using.

Perhaps it's a weird interaction with Eclipse?

But nope: I get it at the command line too:

Error: no `server' JVM at
`C:\PROGRA~1\Java\jre1.6.0\bin\server\jvm.dll'.

Same with the 1.5.0_06 JVM, in case anyone's wondering.

So, it looks like at minimum you need a DLL that isn't installed by
default. (And it looked like the installer installed everything by
default! I didn't find any deselected, installable options to check, at
any rate, and I specifically looked for such because of exactly this
issue when installing 1.6.0.)

In fact, there is no subdirectory "server" in any of the JRE
directories, only "client" subdirectories...
 
M

Mark Jeffcoat

On another note, I see mention of the "server VM". I'd always gathered
that that is just "what you get when you put -server on the command
line", but putting -server on the command line of any of the HotSpot
VMs I've gotten downloading Sun's JDKs and JREs produces an error
message.

As I recall, you only get the client JVM if you
download the standalone JRE; you get both when you
download the full development environment (JDK).
 
T

Twisted

Thomas said:
There's two ways of using References. The most obvious is you read the
reference and check it hasn't gone. The other way is to subclass and
ignore get. The point of subclassing is that when you pick the Reference
off the ReferenceQueue relevant information is available (although not
the actual target object). PhantomReference can be used for cleanup,
much the same as finalisers. Finalisers are, however, easier to write (I
say easier, but to get them correct still isn't easy).

But what can subclassing PhantomReference do for you that finalizers
can't?
Let me guess. You are using Windows.

That one's easy. 90% of the population are, so you're going to guess
right nine out of ten times if you say that. :)
IIRC, the server VM on Windows is
in the JDK but not the JRE. However, you can copy it from the JDK into
the JRE.
Hrm.

There is no AMD64 client VM, but taking the opposite approach from
Windows, if you ask for -d64 -client it silently gives the 64-bit server
VM instead (silently unless you use -showversion, of course).

So I might already be getting it then (64-bit dual core Athlon here).

Nope. Quick commandline test with the 1.6.0 JRE shows "Client VM" in
the version string. Looks like the AMD64 remark is dead wrong, or the
installer stupidly installed a generic-x86 VM even though it could peek
at my system specs and decide what to download.
Yup. Also note trig functions in particular will run faster on non-x86
processors, as the x87 is too imprecise for the Java specification.

Won't this vary modulo -strictfp? (Of course, for some scientific uses,
-strictfp is needed for best results, as opposed to speediest results.)
 
T

Twisted

Mark said:
As I recall, you only get the client JVM if you
download the standalone JRE; you get both when you
download the full development environment (JDK).

I have downloaded full JDKs. (1.5.0_06 and 1.6.0, both currently
installed).
 
T

Thomas Hawtin

Twisted said:
Thomas said:
There's two ways of using References. [...]

But what can subclassing PhantomReference do for you that finalizers
can't?

o You don't have to modify the original class.
o The object cannot be resurrected.
o You get to run in a thread of your choosing.
That one's easy. 90% of the population are, so you're going to guess
right nine out of ten times if you say that. :)

My guess is that less than 90% of Java programmers do.
So I might already be getting it then (64-bit dual core Athlon here).

Not unless you explicitly download it. In general you would download the
JRE, then install the 64-bit runtime inside it. If you have it installed
you should see a number of amd64 directories including bin/amd64,
jre/bin/amd64 and jre/lib/amd64.

Installing the 64-bit version may well help performance. (In general
moving to 64-bit just means that addresses take up twice the memory and
twice memory bandwidth. However, x64 has a less insane instruction set
that x86.)
Won't this vary modulo -strictfp? (Of course, for some scientific uses,
-strictfp is needed for best results, as opposed to speediest results.)

It goes further than strictfp.

Tom Hawtin
 
T

Thomas Kellerer

Twisted wrote on 14.11.2006 16:57:
But nope: I get it at the command line too:

Error: no `server' JVM at
`C:\PROGRA~1\Java\jre1.6.0\bin\server\jvm.dll'.

Same with the 1.5.0_06 JVM, in case anyone's wondering.

So, it looks like at minimum you need a DLL that isn't installed by
default. (And it looked like the installer installed everything by
default! I didn't find any deselected, installable options to check, at
any rate, and I specifically looked for such because of exactly this
issue when installing 1.6.0.)

As others have mentioned, the server VM is only available when using the JDK,
but you are using a JRE not a JDK!

Download the full JDK and point Eclipse to that.

Thomas
 
T

Twisted

Thomas said:
Twisted said:
Thomas said:
There's two ways of using References. [...]

But what can subclassing PhantomReference do for you that finalizers
can't?

o You don't have to modify the original class.

Ah -- so you can use a PhantomReference to make a "finalizer" run when,
say, a particular String gets gc'd, or something else that isn't of a
class you wrote.
o The object cannot be resurrected.

Finalizers can do this? I suppose by putting a strong reference to the
object somewhere that is strongly reachable and will still be strongly
reachable after the finalizer exits.
o You get to run in a thread of your choosing.

As opposed to some system thread you don't want to hold up doing some
lengthy crunching; you can poll the queue from the event dispatch
thread if you want to change something in a GUI in your "finalizer"
without messing around with invokeLater() and generating unreadable
code full of anonymous inner classes/cluttering your source directory
with still more tiny non-anonymous classes on top of all those little
exception classes; etc.
My guess is that less than 90% of Java programmers do.

80% then? :)
Not unless you explicitly download it. In general you would download the
JRE, then install the 64-bit runtime inside it. If you have it installed
you should see a number of amd64 directories including bin/amd64,
jre/bin/amd64 and jre/lib/amd64.

Installing the 64-bit version may well help performance. (In general
moving to 64-bit just means that addresses take up twice the memory and
twice memory bandwidth. However, x64 has a less insane instruction set
that x86.)

And you get these special binaries where, and install them how (if not
self-explanatory once you have them)? (The installer didn't do it
automatically, and the download links on Sun's site include links for
64-bit binaries for 64-bit Windows, but not 64-bit binaries for 32-bit
windows. Although I have e.g. 64-bit binaries for Quake IV and the like
here...)
It goes further than strictfp.

StrictMath then?
 

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,769
Messages
2,569,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top