G1 не обрабатывает мягкие ссылки

Вот мой простой тест gc:

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.

2 ответа

Решение

Возможно, вы путаете со слабыми ссылками?

GC не обязан собирать мягкие ссылки, если только он не оказывается под сильным давлением памяти.

Смотрите здесь для получения дополнительной информации.

В частности, обратите внимание на следующую цитату из документации:

Мягкие ссылочные объекты, которые очищаются по усмотрению сборщика мусора в ответ на запрос памяти.

Единственная реальная гарантия, которую предлагает документация, заключается в следующем:

Все программные ссылки на объекты с мягким доступом гарантированно будут очищены до того, как виртуальная машина сгенерирует OutOfMemoryError.

Есть -XX:SoftRefLRUPolicyMSPerMB= (по умолчанию =1000), который определяет скорость сбора мягких ссылок. Более низкие значения заставляют его собирать их быстрее.

Я не знаю, как это взаимодействует с регионами G1. Вполне возможно, что некоторые регионы редко затрагиваются, и поэтому их мягкие ссылки не учитываются.

Как упомянул @sstan, WeakReferences может предложить несколько более предсказуемое поведение за счет более короткого времени жизни ссылок.


Другая проблема заключается в том, что вы не очищаете список обнуленных объектов со ссылками. Если вы зарегистрируете ссылки в очереди ссылок, опросите эту очередь во время после сна (1000) для ссылок и удалите их из списка, вам не следует исчерпывать память. Для более быстрого поиска набор может быть более подходящим, чем список.

Другие вопросы по тегам