Подтвердить что ты не робот

Что заставляет сборщик мусора G1 в Java 7 прервать свою фазу параллельной метки?

Я заметил случайный полный GC в своем приложении, используя сборщик мусора G1, и пытаюсь выяснить, почему они происходят.

Ниже приводится цикл из одного участка сканирования-начала в следующий. На этапе 61807.406 регистрируется полный GC, за которым следует запись для одновременной отмены-отмены. То, что я хочу знать, - это то, почему GC почувствовала необходимость сделать полную, стоп-мир, сборку мусора и как я могу ее избежать.

Обратите внимание, что этот вопрос, по-видимому, ранее был задан в списке рассылки OpenJDK без ответов.

Я сократил детали молодых GC для краткости, но я могу разместить полный фрагмент где-нибудь, если это необходимо.

61805.878: [GC concurrent-root-region-scan-start]
61805.882: [GC concurrent-root-region-scan-end, 0.0033586]
61805.882: [GC concurrent-mark-start]
61806.133: [GC pause (young), 0.02836202 secs]
   [Eden: 498M(498M)->0B(478M) Survivors: 14M->34M Heap: 3025M(4096M)->2548M(4096M)]
 [Times: user=0.19 sys=0.00, real=0.03 secs] 
61806.426: [GC pause (young), 0.02766222 secs]
   [Eden: 478M(478M)->0B(480M) Survivors: 34M->32M Heap: 3050M(4096M)->2576M(4096M)]
 [Times: user=0.19 sys=0.00, real=0.03 secs] 
61806.717: [GC pause (young), 0.02214895 secs]
   [Eden: 480M(480M)->0B(502M) Survivors: 32M->10M Heap: 3056M(4096M)->2571M(4096M)]
 [Times: user=0.09 sys=0.00, real=0.02 secs] 
61807.000: [GC pause (young), 0.01899188 secs]
   [Eden: 502M(502M)->0B(502M) Survivors: 10M->10M Heap: 3074M(4096M)->2573M(4096M)]
 [Times: user=0.09 sys=0.00, real=0.02 secs] 
61807.201: [GC pause (young), 0.02619259 secs]
   [Eden: 162M(502M)->0B(500M) Survivors: 10M->12M Heap: 3036M(4096M)->2876M(4096M)]
 [Times: user=0.11 sys=0.00, real=0.03 secs] 
61807.283: [GC pause (young), 0.02068515 secs]
   [Eden: 102M(500M)->0B(500M) Survivors: 12M->12M Heap: 3058M(4096M)->2957M(4096M)]
 [Times: user=0.09 sys=0.00, real=0.02 secs] 
61807.350: [GC pause (young), 0.01606520 secs]
   [Eden: 52M(500M)->0B(498M) Survivors: 12M->14M Heap: 3020M(4096M)->2969M(4096M)]
 [Times: user=0.11 sys=0.00, real=0.02 secs] 
61807.389: [GC pause (young), 0.01573865 secs]
   [Eden: 42M(498M)->0B(500M) Survivors: 14M->12M Heap: 3021M(4096M)->2978M(4096M)]
 [Times: user=0.09 sys=0.00, real=0.02 secs] 
61807.406: [Full GC 2978M->2498M(4096M), 4.8896638 secs]
 [Times: user=6.37 sys=0.08, real=4.89 secs] 
61812.296: [GC concurrent-mark-abort]
61812.542: [GC pause (young), 0.01526403 secs]
   [Eden: 512M(500M)->0B(510M) Survivors: 0B->2048K Heap: 3018M(4096M)->2506M(4096M)]
 [Times: user=0.09 sys=0.00, real=0.02 secs] 
61812.793: [GC pause (young) (initial-mark), 0.01391544 secs]
   [Eden: 510M(510M)->0B(508M) Survivors: 2048K->4096K Heap: 3016M(4096M)->2508M(4096M)]
 [Times: user=0.09 sys=0.00, real=0.01 secs] 
61812.807: [GC concurrent-root-region-scan-start]

Это использование версии Java Hotspot 1.7.0_7 со следующими интересными настройками:

-XX:PermSize=128m
-XX:MaxPermSize=128m
-XX:NewSize=512m
-XX:MaxNewSize=512m
-Xms4096m
-Xmx4096m
-XX:+UnlockDiagnosticVMOptions
-XX:+UnsyncloadClass
-XX:+UseTLAB
-XX:+UseG1GC
-XX:SurvivorRatio=10
-Xloggc:./workspace/gc.log
-verbose:gc
-XX:+PrintGC
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
4b9b3361

Ответ 1

Я полагаю, вы знаете о этой ссылке. Эта страница также полезна.

Полный GC возникает, когда объекты, находящиеся на хранении - те, кто выживает в коллекции в эфемерном (молодом) поколении, заполняют пространство, выделенное для них. Когда происходит полный GC, любая эфемерная маркировка, которая была в процессе, должна быть прервана.

Уменьшение скорости, с которой заполняется поколение поколений, требует либо добавления большего количества кучи/оперативной памяти, либо путаницы с разделением доступной памяти между жилыми и юными пространствами. Для последнего используются параметры NewSize, MaxNewSize и NewRatio. Эксперимент - это единственный способ найти то, что будет работать.

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

Это не похоже на ваш случай: 2978M->2498M. Ваш единственный выход может состоять в том, чтобы сделать кучу больше, покупая больше памяти по мере необходимости. Тем не менее, почти все системы, которые работают долгое время, будут иметь полную коллекцию время от времени.