2012-10-29 1 views
13

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

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

Отметьте, что this question похоже, было задано ранее в списке рассылки 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 

ответ

7

Я полагаю, вы знаете о this reference. This page также полезен.

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

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

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

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

+0

Пара q: «Полные GC происходят, когда объекты, на которых хранятся объекты ... заполняют пространство, выделенное для них». Мое пространство для хранения должно составлять 3,5 г (4 г кучи - 512 м MaxNewSize). Из молодых коллекций, непосредственно перед полным gc, похоже, что количество данных в нем было 3g. 3.5> 3, поэтому я думаю, что не полный и не GC. Я неверно истолковываю это? – sharakan

+0

«Тем не менее, почти все системы, которые работают долгое время, будут иметь полную коллекцию время от времени». Я знаю, что это верно с CMS в Java6, хотя, на мой взгляд, в основном из-за фрагментации. Я подумал, что с G1 это будет только в том случае, если маркирующие нити просто не могут идти в ногу с мусорным производством, которое с надлежащей настройкой следует избегать. Любая причина, по которой вы думаете, что с G1 вам придется иногда запускать полный gc? – sharakan

+0

G1 использует множество регионов. Полные коллекции возникают, когда продвижение не выполняется: для уплотнения нет пустой области. Чем дольше работает система, тем лучше вероятность того, что в каждом регионе будет хотя бы один живой объект. – Gene

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