views:

199

answers:

3

In order to perform some testing, I'd like to check how my application behaves when some or all of the objects I have stored in a cache of SoftReference'd objects are disposed of.

In order to do this, I'd like to manually clear the references stored in the cached SoftReference objects - simulating the VM disposing of those objects - but only if nothing else currently has a strong reference to that object (which could be the case if another process had recently retrieved the referenced object from the cache).

My application is single-threaded, so I don't need to worry about the soft reachability of a cached object changing as this code is executing. This also means that I don't currently have any locking mechanisms - if I did have, I could possibly have used these to determine whether or not an object was 'being used' and hence strongly reachable, but alas I don't have need of such locking.

One approach I have tried is to create an additional SoftReference to every object stored in the cache which is registered with a ReferenceQueue. My hope was that in doing so, all of the softly reachable objects in the cache would have their additional SoftReference added to the queue, so all I had to do was loop over the queue, and remove those objects from my cache. However, it seems that the GC enqueues softly reachable objects to their respective queues at its leisure, so it is not guaranteed that anything will be added to the queue once I've finished iterating through the objects in the cache.

One thing that I have also looked at is the -XX:SoftRefLRUPolicyMSPerMB JVM option with a very small value. With judicious memory allocation, this will quite probably clear softly reachable objects from the cache for me the moment they are softly reachable, but I'd really like the app to run normally until I receive a request to clear the softly reachable objects from the cache. As a JVM option, I don't believe I can alter this value while my app is running.

So, does anyone have any ideas as to how I can determine whether or not an object is only softly reachable (and hence can be cleared)?

Edit: The a few extra points that may not have been clear:

  • The app will probably be doing useful work at the times that I want to clear these softly reference objects out. So I'd prefer to not try and cause the GC to clear objects out for me.
  • It would be preferable if I could select which softly reachable objects were cleared out.
  • I would like to app to run normally, i.e. using production memory settings. Changing settings in code, which can then be reset back to their production values, is fine.
+1  A: 

IIRC, soft references are guaranteed (in some sense) to be cleared before an OutOfMemoryError is thrown. So, if you allocate lots of memory they should get cleared if the objects is not strongly referenced. (Not tested.)

Tom Hawtin - tackline
Though this *would* clear the cache of any softly referenced objects, I'd prefer to do it without filling the memory up - as the app may well be doing useful work at the same time and I wouldn't want to affect its performance. Plus I'd have to walk a tight balance between allocating enough memory so that the reference are cleared, but not so much that I cause an OutOfMemory error myself. Plus this wouldn't let me be selective about which objects I clear.
Cyphus
A: 

Substitute a weakreference system for your current soft reference system while testing.

The weak reference system will remove an objects with no other incoming references as soon as that happens, instead of waiting for the jvm to run garbage collection.

NSherwin
No, you always have to wait for the GC to remove the object; but with a weakreference it should be removed 'as soon as possible' and with a softreference it should be removed only if the JVM is running out of memory...
pgras
A: 

Mixing some answers: as Tom Hawtin said allocate memory till you go outOfMemory, for example with this code:

private void doOutOfMemory() {
    try {
        List<byte[]> list = new ArrayList<byte[]>();
        while (true) {
            list.add(new byte[200 * 1024 * 1024]);
        }
    } catch (OutOfMemoryError ex) {
    }
}

If you wan't to control what objects are cleared, take a strong reference on the objects you want to keep.

You may also use weakReferences instead and only call System.gc() to clear there is no guarantee they will always be cleared...

pgras
Though not quite fulfilling all my requirements, this is probably the closest I'm gonna get.
Cyphus