2015-10-19 4 views
2

У меня есть эта программа:Прямое распределение старого поколения

public static void main(String[] args) { 
     int sum = 0; 
     LinkedList<Integer> ll = new LinkedList<>(); 
     for(int i=0;i<Long.MAX_VALUE;i++) { 
      sum += i; 
      if (sum % 3 == 0){ 
       ll.add(i); 
       if (ll.size() % 1000 == 0) 
        System.out.println("Linked List size: " + ll.size()); 
      } 
     } 
    }` 

То, что я ожидал увидеть было целое число объектов, создаваемых в молодом поколении, некоторые из них добавлены в связанный список перешел к старому поколению. Поэтому я ожидал, что GC молодого поколения будет происходить последовательно с объектами, перемещаемыми в оставшиеся в живых, а затем оттуда до старого поколения. Но то, что я нахожу, это то, что GC GC старого поколения все время происходит, а GC нового поколения вообще не происходит. Это какая-то оптимизация, которую делает JVM? Где объекты создаются в старом поколении напрямую? Как вы можете видеть на рисунке ниже, молодой gc случается только дважды, в то время как старый gc 41 раз.

Далее я попробовал один и тот же код, за исключением того, что вместо добавления целочисленного объекта в связанный список я только что создал новый Object(), и, к моему удивлению, не было никаких молодых или старых gc.

public static void main(String[] args) { 
    int sum = 0; 
    LinkedList<Integer> ll = new LinkedList<>(); 
    for(int i=0;i<Long.MAX_VALUE;i++) { 
     sum += i; 
     Object obj = new Object(); 
    } 
} 

No Young or Old GC

Затем я создал случайные строковые объекты:

public static void main(String[] args) { 
    int sum = 0; 
    LinkedList<Integer> ll = new LinkedList<>(); 
    for(int i=0;i<Long.MAX_VALUE;i++) { 
     sum += i; 
     String s = String.valueOf(Math.random()); 
    } 
} 

Теперь я вижу famililar качелей модель с объектами передаются в оставшихся в живых пространств:

5.833: ​​[GC (сбой распределения) [PSYoungGen: 1048576K-> 1984K (1223168K)] 1048576K-> 2000K (4019712K), 0,0035789 s ecs] [Times: user = 0.01 sys = 0.00, real = 0.00 secs] 12.678: [GC (сбой распределения) [PSYoungGen: 1050560K-> 2000K (1223168K)] 1050576K-> 2024K (4019712K), 0,0023286 secs] [Times: user = 0.01 sys = 0.00, real = 0.00 secs] 18.736: [GC (отказ от распределения) [PSYoungGen: 1050576K-> 1968K (1223168K)] 1050600K-> 2000K (4019712K), 0,0016530 secs] [Times: user = 0.01 sys = 0.00, real = 0.00 secs] 24.346: [GC (сбой распределения) [PSYoungGen: 1050544K-> 2000K (1223168K)] 1050576K-> 2040K (4019712K), 0,0016131 secs] [Times: user = 0.01 sys = 0.00, real = 0.00 secs] 31.257: [GC (отказ в распределении) [PSYoungGen: 1050576K-> 1952K (1223168K)] 1050616K-> 2000K (4019712K), 0,0018461 secs] [Times: user = 0.01 sys = 0.00 , real = 0.00 сек.] 38,519: [GC (сбой распределения) [PSYoungGen: 1050528K-> 1984K (1395712K)] 1050576K-> 2040K (4192256K), 0,0022490 сек.] [Times: user = 0.01 sys = 0.00, real = 0.00 secs] 47.998: [GC (Распределение Неудача) [PSYoungGen: 1395648K-> 256K (1394176K)] 1395704K-> 2153K (4190720K), 0.0024607 сек] [Времена: пользователь = 0.01 SYS = 0.00, реальные = 0,00 сек]

Итак, мой вопрос - это ГК достаточно умный, чтобы увидеть, что созданные объекты нигде не используются и отбрасывают их? Почему не со струнами?

ответ

3

В вашем первом примере вы постоянно добавляете объекты к LinkedList, который является самым старым объектом в вашем коде приложения. Как только этот объект будет продвинут на прежнее поколение, добавление объекта в этот список подразумевает модификацию члена старого поколения. Это означает, что следующая сборка мусора должна проверить, доступны ли вновь созданные объекты старым объектом, что на самом деле разумно, как каждый третий объект.

В вашем втором примере вы просто создаете Object без какого-либо побочного эффекта. Такое распределение может быть устранено оптимизатором Hotspot. После этого мусора вообще нет.Фактически, весь цикл может быть устранен, так как дополнения могут быть заменены одним умножением. Но происходит ли это или нет, не имеет значения для деятельности сборщика мусора (или его отсутствия).

В третьем примере вызывается Math.random(), который имеет глобально видимый, не снимаемый эффект. Независимо от того, используете ли вы возвращаемый номер, он будет продвигать состояние генератора глобальных генераторов случайных чисел, который Math.random() использует внутренне. Я полагаю, арифметика генератора псевдослучайных чисел слишком сложна, чтобы позволить преобразовать цикл в один шаг вычисления.

В принципе, создание неиспользуемых экземпляров String по-прежнему может быть устранено, но кажется, что чередование с несъемным кодом затрагивает ограничение оптимизатора. Также может случиться так, что из-за сложности кода генерации случайных чисел создание временной строки считалось не применимым к производительности.

Итак, вы видите, что второй и третий пример имеют мало общего с сборщиком мусора , а скорее с оптимизатором Hotspot. Далее, в отношении вашего первого примера, вам нужно подумать о том, как работает сборщик мусора. Несмотря на это имя, его не обрабатывают мусор, а живые объекты, чтобы узнать, на какие объекты ссылаются живые объекты и, следовательно, живут сами. Поэтому не имеет значения, в каком пространстве генерации создаются объекты, но какой объект может их потенциально достичь. Если ни один старый объект не был изменен со времени последней коллекции, локальная коллекция может быть выполнена, так как немодифицированные старые объекты не могут добраться до молодых людей. Но если старый объект был изменен, его ссылки должны пройти, чтобы узнать, ссылаются ли они на новые объекты.

+0

Итак, мой вопрос в том, почему объекты Integer не созданы в молодом поколении, как ожидалось в моем первом примере. Я ожидал бы, что целое число будет создано в молодое поколение, а затем ссылка на эту переменную будет добавлена ​​в список, а развертка молодого поколения переместит эти объекты в старые. –

+0

Вы делаете неправильные выводы. Как уже было сказано, старая коллекция gen * не означает, что объекты были * созданы * в старом пространстве. Это просто означает, что старое поколение было обработано во время gc, либо потому, что оно было изменено, либо потому, что вся выделенная в настоящий момент память заполнена. Фактически, ваше пространство Eden содержит колоссальные ** 1GB ** объектов, поэтому действительно странно утверждать, что объект был создан в пространстве старого поколения. – Holger

+0

Кажется, у вас очень высокая настройка '-Xms'. Я предлагаю понизить (или удалить) эту настройку и вставить задержку в начале программы, а затем посмотреть, как программа ведет себя * до того, как вся память исчерпана ... – Holger

Смежные вопросы