Генерирование меньшего количества мусора вызывает более длительные паузы GC
Недавно мы внесли изменения в механизм персистентности нашего приложения, заменив медленную сериализацию на рефлексию, чтобы создать строки операторов SQL, которые выполнялись для базы данных MySQL, с сериализацией через OpenHFT Chronicle, с жестко закодированными добавлениями полей различных объектов к отрывку. Как и ожидалось, это сократило время, необходимое для существенного сохранения транзакции, и уменьшило нашу задержку. Но мы заметили что-то загадочное в шаблоне сборки мусора до и после изменения. В то время как мы производили меньше мусора, время, затрачиваемое каждой сборкой мусора, росло, и нам трудно понять, почему.
Вот пример двух запусков, до и после изменения, с одинаковыми аргументами виртуальной машины, работающими с Java 1.8.0_74 в RedHat 4.4.7 CentOS 6.7. Запуск "После", по-видимому, потребляет меньше молодого поколения и меньше общего в начале каждого GC, примерно ту же кучу в конце GC, но требует гораздо больше времени для фактического запуска GC и запуска гораздо реже (около 300 с между ГК вместо 70-80 с).
Мы пытаемся выяснить, как это происходит, и можем ли мы что-то сделать, чтобы вернуть паузы GC туда, где они были, когда мы генерируем мусор намного быстрее. Есть ли что-то в Chronicle и в том, как он использует файлы, отображаемые вне кучи памяти, что вызывает это? Это кажется маловероятным, но, похоже, это имеет значение, если только это не просто образец того, как генерируется мусор. FWIW, в качестве эксперимента мы попробовали и G1, и CMS, и, по крайней мере, с параметрами по умолчанию, они показывают ту же схему и, если что-нибудь, худшие времена.
VM args:
-Xms75776M
-Xmx75776M
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Dsun.rmi.dgc.server.gcInterval=54000000
-Dsun.rmi.dgc.client.gcinterval=54000000
-XX:+DisableExplicitGC
-XX:MaxNewSize=19000M
-XX:+PrintGCApplicationStoppedTime
-XX:InitialSurvivorRatio=3
До:
15009.601: [GC (Allocation Failure) [PSYoungGen: 19226640K->142320K(19273216K)] 22796282K->3814635K(77411840K), 0.0596127 secs] [Times: user=0.53 sys=0.05, real=0.06 secs]
15080.410: [GC (Allocation Failure) [PSYoungGen: 19235824K->137920K(19282432K)] 22908139K->3913367K(77421056K), 0.0570436 secs] [Times: user=0.50 sys=0.06, real=0.06 secs]
15154.485: [GC (Allocation Failure) [PSYoungGen: 19243712K->129840K(19279360K)] 23019159K->4007451K(77417984K), 0.0605860 secs] [Times: user=0.55 sys=0.05, real=0.06 secs]
.
.
bunch of lines omitted to get to approximately the same end-point
.
16070.663: [GC (Allocation Failure) [PSYoungGen: 19195664K->146464K(19262976K)] 24408408K->5460932K(77401600K), 0.0616580 secs] [Times: user=0.55 sys=0.06, real=0.06 secs]
После:
15313.256: [GC (Allocation Failure) [PSYoungGen: 15092194K->2230066K(15050752K)] 16440428K->3981360K(73189376K), 0.3563350 secs] [Times: user=3.40 sys=0.15, real=0.36 secs]
15770.413: [GC (Allocation Failure) [PSYoungGen: 15050546K->2922738K(15321600K)] 16801840K->4674033K(73460224K), 0.3584541 secs] [Times: user=3.56 sys=0.00, real=0.36 secs]
16090.016: [GC (Allocation Failure) [PSYoungGen: 14896370K->3571346K(15244288K)] 16647665K->5322641K(73382912K), 0.4276084 secs] [Times: user=4.25 sys=0.00, real=0.42 secs]
Обновление: Итак, я выполнил следующий эксперимент, основываясь на некоторых советах ниже (это на машине с UAT, а не на машине PROD, так что она немного отличается... например, версия linux - CentOS 7.2 вместо 6.7). Мы ограничиваем размер кучи 32G и устанавливаем явную цель GC-паузы в 200 мс, а также включаем больше диагностической информации. Во всяком случае, результаты еще хуже. Это начинается довольно разумно, но дует прямо в течение предложенного времени паузы до 1,94 секунды.
java -XX:MaxGCPauseMillis=200 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -Dsun.rmi.dgc.server.gcInterval=54000000 -Dsun.rmi.dgc.client.gcinterval=54000000 -XX:+DisableExplicitGC -Xms32000M -Xmx32000M
{Heap before GC invocations=1 (full 0):
PSYoungGen total 9557504K, used 4096257K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 50% used [0x00007f58fe580000,0x00007f59f85c0458,0x00007f5af2600000)
from space 1364992K, 0% used [0x00007f5b45b00000,0x00007f5b45b00000,0x00007f5b99000000)
to space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af2600000,0x00007f5b45b00000)
ParOldGen total 21845504K, used 0K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9000000,0x00007f58fe580000)
Metaspace used 20877K, capacity 21118K, committed 21296K, reserved 1069056K
class space used 2499K, capacity 2599K, committed 2608K, reserved 1048576K
2.420: [GC (Metadata GC Threshold)
Desired survivor size 1397751808 bytes, new threshold 7 (max 15)
[PSYoungGen: 4096257K->13270K(9557504K)] 4096257K->13366K(31403008K), 0.0181755 secs] [Times: user=0.11 sys=0.05, real=0.02 secs]
Heap after GC invocations=1 (full 0):
PSYoungGen total 9557504K, used 13270K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 0% used [0x00007f58fe580000,0x00007f58fe580000,0x00007f5af2600000)
from space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af32f59a8,0x00007f5b45b00000)
to space 1364992K, 0% used [0x00007f5b45b00000,0x00007f5b45b00000,0x00007f5b99000000)
ParOldGen total 21845504K, used 96K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9018010,0x00007f58fe580000)
Metaspace used 20877K, capacity 21118K, committed 21296K, reserved 1069056K
class space used 2499K, capacity 2599K, committed 2608K, reserved 1048576K
}
{Heap before GC invocations=2 (full 1):
PSYoungGen total 9557504K, used 13270K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 0% used [0x00007f58fe580000,0x00007f58fe580000,0x00007f5af2600000)
from space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af32f59a8,0x00007f5b45b00000)
to space 1364992K, 0% used [0x00007f5b45b00000,0x00007f5b45b00000,0x00007f5b99000000)
ParOldGen total 21845504K, used 96K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9018010,0x00007f58fe580000)
Metaspace used 20877K, capacity 21118K, committed 21296K, reserved 1069056K
class space used 2499K, capacity 2599K, committed 2608K, reserved 1048576K
2.438: [Full GC (Metadata GC Threshold) [PSYoungGen: 13270K->0K(9557504K)] [ParOldGen: 96K->12747K(21845504K)] 13366K->12747K(31403008K), [Metaspace: 20877K->20877K(1069056K)], 0.0530698 secs] [Times: user=0.27 sys=0.05, real=0.05 secs]
Heap after GC invocations=2 (full 1):
PSYoungGen total 9557504K, used 0K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 0% used [0x00007f58fe580000,0x00007f58fe580000,0x00007f5af2600000)
from space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af2600000,0x00007f5b45b00000)
to space 1364992K, 0% used [0x00007f5b45b00000,0x00007f5b45b00000,0x00007f5b99000000)
ParOldGen total 21845504K, used 12747K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9c72e90,0x00007f58fe580000)
Metaspace used 20877K, capacity 21118K, committed 21296K, reserved 1069056K
class space used 2499K, capacity 2599K, committed 2608K, reserved 1048576K
}
{Heap before GC invocations=3 (full 1):
PSYoungGen total 9557504K, used 8192512K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 100% used [0x00007f58fe580000,0x00007f5af2600000,0x00007f5af2600000)
from space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af2600000,0x00007f5b45b00000)
to space 1364992K, 0% used [0x00007f5b45b00000,0x00007f5b45b00000,0x00007f5b99000000)
ParOldGen total 21845504K, used 12747K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9c72e90,0x00007f58fe580000)
Metaspace used 22891K, capacity 23188K, committed 23472K, reserved 1071104K
class space used 2602K, capacity 2688K, committed 2736K, reserved 1048576K
1332.241: [GC (Allocation Failure)
Desired survivor size 1397751808 bytes, new threshold 7 (max 15)
[PSYoungGen: 8192512K->291885K(9557504K)] 8205259K->304649K(31403008K), 0.2443282 secs] [Times: user=0.48 sys=3.83, real=0.25 secs]
Heap after GC invocations=3 (full 1):
PSYoungGen total 9557504K, used 291885K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 0% used [0x00007f58fe580000,0x00007f58fe580000,0x00007f5af2600000)
from space 1364992K, 21% used [0x00007f5b45b00000,0x00007f5b5780b650,0x00007f5b99000000)
to space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af2600000,0x00007f5b45b00000)
ParOldGen total 21845504K, used 12763K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9c76e90,0x00007f58fe580000)
Metaspace used 22891K, capacity 23188K, committed 23472K, reserved 1071104K
class space used 2602K, capacity 2688K, committed 2736K, reserved 1048576K
}
{Heap before GC invocations=4 (full 1):
PSYoungGen total 9557504K, used 8484397K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 100% used [0x00007f58fe580000,0x00007f5af2600000,0x00007f5af2600000)
from space 1364992K, 21% used [0x00007f5b45b00000,0x00007f5b5780b650,0x00007f5b99000000)
to space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af2600000,0x00007f5b45b00000)
ParOldGen total 21845504K, used 12763K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9c76e90,0x00007f58fe580000)
Metaspace used 22939K, capacity 23252K, committed 23472K, reserved 1071104K
class space used 2602K, capacity 2688K, committed 2736K, reserved 1048576K
2858.320: [GC (Allocation Failure)
Desired survivor size 1397751808 bytes, new threshold 7 (max 15)
[PSYoungGen: 8484397K->677978K(9557504K)] 8497161K->690750K(31403008K), 0.5290410 secs] [Times: user=0.74 sys=8.70, real=0.53 secs]
Heap after GC invocations=4 (full 1):
PSYoungGen total 9557504K, used 677978K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 0% used [0x00007f58fe580000,0x00007f58fe580000,0x00007f5af2600000)
from space 1364992K, 49% used [0x00007f5af2600000,0x00007f5b1bc16a80,0x00007f5b45b00000)
to space 1364992K, 0% used [0x00007f5b45b00000,0x00007f5b45b00000,0x00007f5b99000000)
ParOldGen total 21845504K, used 12771K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9c78e90,0x00007f58fe580000)
Metaspace used 22939K, capacity 23252K, committed 23472K, reserved 1071104K
class space used 2602K, capacity 2688K, committed 2736K, reserved 1048576K
}
{Heap before GC invocations=5 (full 1):
PSYoungGen total 9557504K, used 8870490K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 100% used [0x00007f58fe580000,0x00007f5af2600000,0x00007f5af2600000)
from space 1364992K, 49% used [0x00007f5af2600000,0x00007f5b1bc16a80,0x00007f5b45b00000)
to space 1364992K, 0% used [0x00007f5b45b00000,0x00007f5b45b00000,0x00007f5b99000000)
ParOldGen total 21845504K, used 12771K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9c78e90,0x00007f58fe580000)
Metaspace used 22946K, capacity 23252K, committed 23472K, reserved 1071104K
class space used 2602K, capacity 2688K, committed 2736K, reserved 1048576K
4467.385: [GC (Allocation Failure)
Desired survivor size 1397751808 bytes, new threshold 7 (max 15)
[PSYoungGen: 8870490K->1096779K(9557504K)] 8883262K->1109558K(31403008K), 0.9701847 secs] [Times: user=1.96 sys=15.40, real=0.97 secs]
Heap after GC invocations=5 (full 1):
PSYoungGen total 9557504K, used 1096779K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 0% used [0x00007f58fe580000,0x00007f58fe580000,0x00007f5af2600000)
from space 1364992K, 80% used [0x00007f5b45b00000,0x00007f5b88a12d00,0x00007f5b99000000)
to space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af2600000,0x00007f5b45b00000)
ParOldGen total 21845504K, used 12779K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9c7ae90,0x00007f58fe580000)
Metaspace used 22946K, capacity 23252K, committed 23472K, reserved 1071104K
class space used 2602K, capacity 2688K, committed 2736K, reserved 1048576K
}
{Heap before GC invocations=6 (full 1):
PSYoungGen total 9557504K, used 9289291K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 100% used [0x00007f58fe580000,0x00007f5af2600000,0x00007f5af2600000)
from space 1364992K, 80% used [0x00007f5b45b00000,0x00007f5b88a12d00,0x00007f5b99000000)
to space 1364992K, 0% used [0x00007f5af2600000,0x00007f5af2600000,0x00007f5b45b00000)
ParOldGen total 21845504K, used 12779K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 0% used [0x00007f53c9000000,0x00007f53c9c7ae90,0x00007f58fe580000)
Metaspace used 22951K, capacity 23252K, committed 23472K, reserved 1071104K
class space used 2602K, capacity 2688K, committed 2736K, reserved 1048576K
6153.256: [GC (Allocation Failure)
Desired survivor size 2375548928 bytes, new threshold 6 (max 15)
[PSYoungGen: 9289291K->1364987K(9557504K)] 9302070K->2238887K(31403008K), 1.9590450 secs] [Times: user=5.38 sys=29.68, real=1.96 secs]
Heap after GC invocations=6 (full 1):
PSYoungGen total 9557504K, used 1364987K [0x00007f58fe580000, 0x00007f5b99000000, 0x00007f5b99000000)
eden space 8192512K, 0% used [0x00007f58fe580000,0x00007f58fe580000,0x00007f5af2600000)
from space 1364992K, 99% used [0x00007f5af2600000,0x00007f5b45afed70,0x00007f5b45b00000)
to space 1364992K, 0% used [0x00007f5b45b00000,0x00007f5b45b00000,0x00007f5b99000000)
ParOldGen total 21845504K, used 873899K [0x00007f53c9000000, 0x00007f58fe580000, 0x00007f58fe580000)
object space 21845504K, 4% used [0x00007f53c9000000,0x00007f53fe56ae90,0x00007f58fe580000)
Metaspace used 22951K, capacity 23252K, committed 23472K, reserved 1071104K
class space used 2602K, capacity 2688K, committed 2736K, reserved 1048576K
}
3 ответа
Вы беспокоитесь о времени паузы, но вы не устанавливаете цель времени паузы (MaxGCPauseMillis
). Коллектор по умолчанию (ParallelGC) не имеет цели времени паузы по умолчанию, поэтому вы должны указать ее явно.
Когда установлено, GC будет пытаться отрегулировать размер молодого поколения и пороговые значения пребывания для достижения этих целей.
FWIW, в качестве эксперимента мы попробовали и G1, и CMS, и, по крайней мере, с параметрами по умолчанию, они показывают ту же схему и, если что-нибудь, худшие времена.
G1 имеет заданную по умолчанию цель паузы в 200 мс, поэтому увеличение времени паузы в этом диапазоне не будет неожиданным.
Я бы посоветовал держать кучу ниже 32 ГБ, чтобы вы могли использовать сжатые ой.
Имея больше коллекций, вы можете со временем распределять работу. Я бы тоже попробовал пропустить новое пространство.
Вам нужна более подробная статистика, рассмотрите что-то вроде visualgc, чтобы наблюдать за тем, что происходит в разных частях кучи, когда нагрузка развивается и помечается как -XX:+PrintTenuringDistribution
для углубления в то, что происходит в связанных с Эдемом пространствах.
Тот факт, что общий размер кучи увеличивается и увеличивается во 2-м случае, говорит о том, что вы постепенно истекаете кровью, так что увеличенное время может быть связано с тем, что выжившие пингуются между пространствами от и до (и затем в конечном итоге повышаются до штатный). Обратите внимание, что это предположение, основанное на доступных данных, нам нужна более подробная статистика, чтобы действительно понять, что происходит (или понимание того, как ведет себя хроника, чего у меня лично нет).
Это может означать, что у вас есть утечка памяти или что eden теперь просто слишком мал (с точки зрения максимального порога или просто размера eden, вообще говоря, может потребоваться некоторая настройка eden, чтобы соответствовать вашему новому образцу использования кучи).