How can I force release soft reference

1.3k Views Asked by At

I know soft reference will only release when the JVM is running low on memory. How can I do it manually?

My code:

  Object object = new Object();
  ReferenceQueue queue = new ReferenceQueue();
  SoftReference softReference= new SoftReference(object, queue);
  object = null;
  System.gc();
  //now I force release soft reference.

Is there a solution in the latest java versions (8-11)?

3

There are 3 best solutions below

0
Holger On BEST ANSWER

As you said, softly reachable objects get collected when there is memory pressure and one way to enforce this, is to create actual memory pressure.

E.g. the following code

Object object = new Object();
ReferenceQueue queue = new ReferenceQueue();
SoftReference softReference= new SoftReference(object, queue);
new Thread(() -> {
    try {
        queue.remove();
        System.out.println("collected");
    } catch (InterruptedException ex) {}
}).start();
object = null;
try {
    object = new int[10][10][10][10][10][10][10][10][10][10][10][10];
} catch(OutOfMemoryError err) {
    System.out.println("...");
}

prints

collected
...

on my machine.

The code example above follows the idea to trigger the behavior by an allocation request that will definitely fail, but to prevent the JVM from detecting that it will never succeed, as when the JVM detects that an allocation can never succeed, regardless of the garbage collector’s effort, it may skip the garbage collection (and hence, the clearing of soft references).

The multi-dimensional array allocation, which is an array of arrays in Java, seems to confuse the current implementation enough, so it does actually try. An alternative approach using plain arrays, is to allocate in a loop, starting with a small size and raise it until failure.

There’s still the risk that the JVM’s optimizer detects that the allocated object is never used and eliminates the allocation completely, however, this rarely happens for code which is executed only once.

If the only desired effect, is to have the SoftReference cleared and enqueued, e.g. to test the handling code, you could simply invoke clear(), followed by enqueue() on the reference object.

Object object = new Object();
ReferenceQueue queue = new ReferenceQueue();
SoftReference softReference= new SoftReference(object, queue);
new Thread(() -> {
    try { queue.remove(); } catch (InterruptedException ex) {}
Object object = new Object();
ReferenceQueue queue = new ReferenceQueue();
SoftReference softReference= new SoftReference(object, queue);
new Thread(() -> {
    try {
        queue.remove();
        System.out.println("collected");
    } catch (InterruptedException ex) {}
}).start();
object = null;

Thread.sleep(500);
softReference.clear();
softReference.enqueue();

When the soft reference was the only reference to the object, clearing it makes the object also eligible to normal garbage collection, regardless of the actual memory pressure.

3
Vadim On
  1. In general you cannot: System.gc(); is only advise to JVM to run GC

  2. only when I have no memory - this is quite not right. GC works a litle more complex than that and there are bunch of setting for GC on JVM level...

0
Arpit Shah On
  • System.gc() may not ever run depending on the threshold set before garbage collection kicks in.
  • One option is to adjust -XX:SoftRefLRUPolicyMSPerMB=2500 parameter in your JVM configuration. This means that any soft referenced item will be deleted in 2.5 seconds. Hopefully that helps.