1

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

Chris K
  • 11,622
  • 1
  • 36
  • 49
Idan Str
  • 614
  • 1
  • 11
  • 33
  • This is not duplicate, I asked about soft reference. – Idan Str Feb 13 '19 at 22:16
  • https://stackoverflow.com/questions/3785713/how-to-make-the-java-system-release-soft-references – tsolakp Feb 13 '19 at 22:17
  • Why do you need to do this? Test harness? – markspace Feb 13 '19 at 22:20
  • Iv'e been playing around with references and wanted to know if this is possible – Idan Str Feb 13 '19 at 22:32
  • 1
    It is a duplicate, because you can't force garbage collection, and that includes strong, weak, soft, and phantom references. – user207421 Feb 13 '19 at 22:37
  • @user207421 I edit my question, It's not about garbage collection - Its about soft referances testing. – Idan Str Feb 13 '19 at 22:42
  • Why do you call the variable `weakReference` when it holds a reference to a `SoftReference`? And what do you mean with “release”? This is not a technical term. Which actual effect do you want to achieve? – Holger Feb 14 '19 at 11:19
  • @Holger weakReferece was mistake - fix it. i want to see null when i call get() method. – Idan Str Feb 14 '19 at 12:50
  • Then just call `softReference.clear()`. – Holger Feb 14 '19 at 12:54
  • SoftReference can automaticly clear by jvm- I want to simulate it. – Idan Str Feb 14 '19 at 13:00
  • The JVM will clear and enqueue. To simulate this, call `clear()` and `enqueue()` on it. That’s what simulating means. You want to perform an action that has the same effect. Whether that action is calling `System.gc()` or calling `softReference.clear()`+`softReference.enqueue()`, is irrelevant. – Holger Feb 14 '19 at 13:05
  • Thanks alot for your answer – Idan Str Feb 14 '19 at 13:49

3 Answers3

5
  • 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.
Arpit Shah
  • 75
  • 6
2

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.

Holger
  • 285,553
  • 42
  • 434
  • 765
0
  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...

Vadim
  • 4,027
  • 2
  • 10
  • 26
  • Is there any way to simulate it? – Idan Str Feb 13 '19 at 22:14
  • as I know there is no way - and that is a Java point - you must not do anything with GC from code. Still put `System.gc()` is not very bad idea and sometime it helps, but not guaranteed. – Vadim Feb 13 '19 at 22:23
  • it is not a problem. Maybe latest versions of Java has something - I did not touch this area for a long enough time and Java goes farther and farther from original basic conceptions. Still there is no much sense to worry about that. – Vadim Feb 13 '19 at 22:26