How to cause soft references to be cleared in Java?
Asked Answered
S

10

21

I have a cache which has soft references to the cached objects. I am trying to write a functional test for behavior of classes which use the cache specifically for what happens when the cached objects are cleared.

The problem is: I can't seem to reliably get the soft references to be cleared. Simply using up a bunch of memory doesn't do the trick: I get an OutOfMemory before any soft references are cleared.

Is there any way to get Java to more eagerly clear up the soft references?


Found here:

"It is guaranteed though that all SoftReferences will get cleared before OutOfMemoryError is thrown, so they theoretically can't cause an OOME."

So does this mean that the above scenario MUST mean I have a memory leak somewhere with some class holding a hard reference on my cached object?

Sweetie answered 19/1, 2009 at 10:54 Comment(0)
W
15

The problem is: I can't seem to reliably get the soft references to be cleared.

This is not unique to SoftReferences. Due to the nature of garbage collection in Java, there is no guarantee that anything that is garbage-collectable will actually be collected at any point in time. Even with a simple bit of code:

Object temp = new Object();
temp = null;
System.gc();

there is no guarantee that the Object instantiated in the first line is garbage collected at this, or in fact any point. It's simply one of the things you have to live with in a memory-managed language, you're giving up declarative power over these things. And yes, that can make it hard to definitively test for memory leaks at times.


That said, as per the Javadocs you quoted, SoftReferences should definitely be cleared before an OutOfMemoryError is thrown (in fact, that's the entire point of them and the only way they differ from the default object references). It would thus sound like there is some sort of memory leak in that you're holding onto harder references to the objects in question.

If you use the -XX:+HeapDumpOnOutOfMemoryError option to the JVM, and then load the heap dump into something like jhat, you should be able to see all the references to your objects and thus see if there are any references beside your soft ones. Alternatively you can achieve the same thing with a profiler while the test is running.

Winter answered 19/1, 2009 at 11:11 Comment(2)
+1 for jhat reference, looks like a very useful tool. Is there anything like this for .NET?Germinative
To answer my own question: microsoft.com/downloads/…Germinative
C
15

There is also the following JVM parameter for tuning how soft references are handled:

-XX:SoftRefLRUPolicyMSPerMB=<value>

Where 'value' is the number of milliseconds a soft reference will remain for every free Mb of memory. The default is 1s/Mb, so if an object is only soft reachable it will last 1s if only 1Mb of heap space is free.

Circumvent answered 2/3, 2009 at 22:46 Comment(0)
J
5

You can force all SoftReferences to be cleared in your tests with this piece of code.

Jason answered 28/9, 2010 at 7:20 Comment(0)
R
2

If you really wanted to, you can call clear() on your SoftReference to clear it.

That said, if the JVM is throwing an OutOfMemoryError and your SoftReference has not been cleared yet, then this means that you must have a hard reference to the object somewhere else. To do otherwise would invalidate the contract of SoftReference. Otherwise, you are never guaranteed that the SoftReference is cleared: as long as there is still memory available, the JVM does not need to clear any SoftReferences. On the other hand, it is allowed to clear them next time it does a GC cycle, even if it doesn't need to.

Also, you can consider looking into WeakReferences since the VM tends to be more aggressive in clear them. Technically, the VM isn't ever required to clear a WeakReference, but it is supposed to clean them up next time it does a GC cycle if the object would otherwise be considered dead. If your are trying to test what happens when your cache is cleared, using WeakReferences should help your entries go away faster.

Also, remember that both of these are dependent on the JVM doing a GC cycle. Unfortunately, there is no way to guarantee that one of those ever happens. Even if you call System.gc(), the garbage collector may decide that it is doing just peachy and choose to do nothing.

Roshelle answered 19/1, 2009 at 14:21 Comment(0)
W
2

In a typical JVM implementation (SUN) you need to trigger a Full GC more than once to get the Softreferences cleaned. The reason for that is because Softreferences require the GC to do more work, because for example of a mechanism that allows you to get notified when the objects are reclaimed.

IMHO using a lot of sofreferences in an application server is evil, because the developer has not much control over when they are released.

Wasteful answered 19/1, 2009 at 16:35 Comment(2)
Agree with the first point (correct, the first time it only takes note of the clock). Disagree with the second point - too general.Racialism
Why do you think it's too general. Ok if you have only one application on your server than it is maybe. But I think that's very rare. And even then the policy is often not what you would want.Wasteful
F
1

Garbage collection and other references like soft references are non deterministic this it's not really possible to reliable do stuff so that soft references are definitely cleared at that point so your test can judge how yourcache reacts. I would suggest you simulate the reference clearing in more definite way by mocking etc - your tests will be reproducable and more valuable rather than just Hopi g for the GC to clean up references. Using the latter approach is a really bad thing to do and willjust introduce additional problems rather than help you improve the quality of your cache and it's collaborating components.

Fulviah answered 19/1, 2009 at 11:9 Comment(1)
But then again the reference-clearing at OOM-time is defined behaviour and is pretty much what he likes to achieve with the SoftReferences (if I understand correctly), so I'd say he should test it.Multinuclear
M
0

From the documentation and my experience I'd say yes: you must have a reference somewhere else.

I'd suggest using a debugger that can show you all references to an object (such as Eclipse 3.4 when debugging Java 6) and just check when the OOM is thrown.

Multinuclear answered 19/1, 2009 at 11:11 Comment(0)
B
0

If you use eclipse, there is this tool named Memory Analyzer that makes heap dump debugging easier.

Barchan answered 19/1, 2009 at 13:51 Comment(0)
L
0

Does the cached object have a finalizer? The finalizer will create new strong references to the object, so even if the SoftReference is cleared the memory will not be reclaimed until a later GC cycle

Limulus answered 16/9, 2009 at 13:21 Comment(0)
G
-2

If you have a cache which is a Map of SoftReferences and you want them cleared you can just clear() the map and they will all be cleaned up (including their references)

Gettings answered 7/3, 2009 at 6:39 Comment(2)
-1. No this is not the same as clearing the references. It only causes the SoftReference to become unreachable (as long as there are no other strong references to the SoftReference.) If the SoftReference is gc'ed as a result then it will not be enqueued. If you were using the ReferenceQueue to notify you when the SoftReference was cleared then this will prevent the cleanup method being called.Limulus
@finw, actually the answer has merits and it's probably the best you can do, if you wish to be notified, do not use the soft-ref but phantom ones along w/ the soft-ref to provide the caching mechanism.Minier

© 2022 - 2024 — McMap. All rights reserved.