G1不处理软引用。

3

这是我的一个简单的垃圾回收测试:

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) {}
  }
}

使用这些参数(启用G1):

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

我使用grep命令来查找输出信息:
grep -E "(Full|GC cleanup)" jvm.log

并获得类似于这样的东西:
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]

在ParallelGc的完整收集期间,软引用似乎被回收了,而并发收集几乎没有起到作用。来自VisualVm的堆转储也证明了这一点。

我是否错过了什么,或者这是G1中的一个错误?

已在1.7.0_51-b13和1.8.0_45-b15 x64上进行了检查。


软引用的行为非常奇怪和不确定。强制垃圾回收器对它们进行任何操作都很困难或不可能。 - Louis Wasserman
看起来这个问题已经在Oracle的bug跟踪器中了,而且它不会很快被关闭:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6912889 - tim zh
2个回答

3

也许您与弱引用混淆了?

除非它发现自己面临严重的内存压力,否则GC不会强制收集软引用。

更多信息请参见此处

特别要注意文档中以下引用:

软引用对象由垃圾回收器在响应内存需求时自行决定是否清除。

文档提供的唯一真正保证如下:

在虚拟机抛出OutOfMemoryError之前,所有对可软到达对象的软引用都已被清除。


谢谢,听起来很合理。 - tim zh

1

有一个 -XX:SoftRefLRUPolicyMSPerMB= (默认值为1000)来控制软引用的收集速率。较低的值会使其更快地被收集。

我不知道它如何与G1的区域交互。可能有些区域很少被访问,因此它们的软引用不会被考虑在内。

正如@sstan所提到的,WeakReferences可能提供更可预测的行为,但代价是引用的寿命要短得多。


另一个问题是您没有清除已置空的软引用对象列表。如果您使用引用队列注册引用,并在睡眠1000毫秒后轮询该队列以获取引用并从列表中删除它们,则不会耗尽内存。为了更快速地查找,集合可能比列表更合适。

遗憾的是,SoftRefLRUPolicyMSPerMB不能帮助消除完整的gcs。 - tim zh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接