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)?
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.