G1 doesn't process soft references

1.2k views Asked by At

Here is my simple gc test:

public class Main {

  static class Data {
    public long[] l = new long[100];
  }

  static List<SoftReference<Data>> list = new ArrayList<>();

  public static void main(String[] args) {
    long i = 0;

    while (true) {
      list.add(new SoftReference<>(new Data()));
      ++i;
      if (i % 1000 == 0) {
        sleep(1);
        if (i % 1_000_000 == 0)
          sleep(1000);
      }
    }
  }

  static void sleep(long millis) {
    try { Thread.sleep(millis); } catch (InterruptedException ignored) {}
  }
}

Using these args (G1 enabled):

java -Xmx2G -Xms2G -XX:MaxPermSize=128m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 
-XX:+PrintAdaptiveSizePolicy -Xloggc:jvm.log -XX:+UseG1GC 
-XX:InitiatingHeapOccupancyPercent=5 Main

I grep the output:

grep -E "(Full|GC cleanup)" jvm.log

and get something like this:

0.564: [GC cleanup 277M->277M(2048M), 0.0009922 secs]
0.879: [GC cleanup 443M->442M(2048M), 0.0009396 secs]
1.676: [GC cleanup 859M->856M(2048M), 0.0008681 secs]
3.530: [GC cleanup 1324M->1320M(2048M), 0.0012422 secs]
4.838: [GC cleanup 1711M->1707M(2048M), 0.0010601 secs]
6.334: [Full GC 2047M->102M(2048M), 1.2659685 secs]
8.322: [GC cleanup 534M->534M(2048M), 0.0009528 secs]
11.250: [GC cleanup 1460M->1450M(2048M), 0.0011207 secs]
13.499: [Full GC 2046M->512M(2048M), 1.3534848 secs]

It seems that soft references were collected during ParallelGc's full collections while concurrent collections were almost useless. Heap dumps from VisualVm also prove this version.

Do I miss something or it is a bug in G1?

Checked on 1.7.0_51-b13 and 1.8.0_45-b15 x64.

2

There are 2 answers

1
sstan On BEST ANSWER

Perhaps you are confusing with weak references?

The GC is not forced to collect soft references, unless it finds itself under severe memory pressure.

See here for more information.

In particular, notice the following quote from the documentation:

Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand.

The only real guarantee the documentation offers is as follows:

All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError.

1
the8472 On

There is -XX:SoftRefLRUPolicyMSPerMB= (default=1000) that governs the collection rate of soft references. Lower values make it collect them faster.

I don't know how it interacts with G1's regions. It's possible that some regions are rarely touched and thus their soft references don't get taken into account.

As @sstan mentioned WeakReferences may offer somewhat more predictable behavior at the expense of much shorter lifetimes of the references.


Another problem is that you do not clear the list of nulled-out softreference objects. If you register the refs with a reference queue, poll that queue during after the sleep(1000) for references and remove them from the list you should not run out of memory. For faster lookup a set might be more suitable than a list.