Я часто встречал свое занятое Java-приложение с полным gc.
И я контролировал процесс с помощью jstat и получил следующий результат:
Timestamp S0 S1 E O P YGC YGCT FGC FGCT GCT LGCC GCC
2265116.2 0.00 58.20 79.23 62.57 62.29 273122 5729.765 727 281.867 6011.632 unknown GCCause No GC
2265117.3 0.00 58.20 86.92 62.57 62.29 273122 5729.765 727 281.867 6011.632 unknown GCCause No GC
2265118.3 0.00 58.20 97.72 62.57 62.29 273122 5729.765 727 281.867 6011.632 unknown GCCause No GC
2265119.3 48.51 0.00 13.06 62.84 62.29 273123 5729.791 727 281.867 6011.658 unknown GCCause No GC
2265120.2 48.51 0.00 51.12 62.84 62.29 273123 5729.791 727 281.867 6011.658 unknown GCCause No GC
2265121.3 0.00 42.79 35.43 65.35 62.29 273124 5729.830 727 281.867 6011.697 unknown GCCause No GC
2265122.2 0.00 39.46 50.81 80.86 62.29 273126 5729.998 728 281.883 6011.881 CMS Initial Mark No GC
2265123.3 4.43 4.82 75.57 97.05 62.29 273129 5730.176 729 281.883 6012.060 unknown GCCause Allocation Failure
2265124.3 4.43 4.82 75.57 97.05 62.29 273129 5730.176 729 281.883 6012.060 unknown GCCause Allocation Failure
2265125.3 0.00 7.89 26.93 45.03 62.27 273130 5730.259 729 283.690 6013.949 unknown GCCause No GC
2265126.3 0.00 7.89 35.96 45.03 62.27 273130 5730.259 729 283.690 6013.949 unknown GCCause No GC
2265127.3 0.00 7.89 44.85 45.03 62.27 273130 5730.259 729 283.690 6013.949 unknown GCCause No GC
2265128.3 0.00 7.89 52.71 45.03 62.27 273130 5730.259 729 283.690 6013.949 unknown GCCause No GC
2265129.3 0.00 7.89 61.61 45.03 62.27 273130 5730.259 729 283.690 6013.949 unknown GCCause No GC
Я мог видеть, что каждые 20 минут или около того, кажется, очень огромный объект, созданный в памяти. Он настолько велик, что не может вписаться в молодое поколение, он напрямую передается в старом гене.
И это часто приводит к тому, что все приложение попадает в ретус FGC (что составляет 70%) и срабатывает FGC, поэтому большой объект GC-ed немедленно. Поэтому я не мог определить, что это за кучи кучи.
Эта проблема регулярно меняет приложение "землетрясения".
Моя максимальная куча составляет 3 г, а молодняк - 521 м. Перм-ген всегда стабилен.
Итак, может кто-нибудь сказать мне, как я могу узнать, что такое огромный объект?
Могу ли я настроить jvm для выгрузки своей памяти, когда old-gen превышает некоторое заданное соотношение?
Или могут помочь другие полезные методологии?
Огромное спасибо!
Существует флаг JVM, который может вам пригодиться: -XX:+HeapDumpBeforeFullGC
. Это заставит JVM сбрасывать всю кучу в файл перед крупным глобальным GC. Флаг управляемый. Это означает, что вы можете включать/отключать его во время выполнения через JMX с помощью JConsole, Misson Control или даже программно с помощью javax.management
API:
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(
server,
"com.sun.management:type=HotSpotDiagnostic",
HotSpotDiagnosticMXBean.class);
bean.setVMOption("HeapDumpBeforeFullGC", "true");
Если большой объект GC-ed от FullGC, вы можете использовать гистограмму класса для проверки кучи.
Используйте -XX:+PrintClassHistogramBeforeFullGC
и -XX:+PrintClassHistogramAfterFullGC.
Это, по крайней мере, покажет вам все классы классов, выделенные в куче, отсортированные по площади и количеству экземпляров.
Это легкий подход, но вы можете хотя бы проверить свою гипотезу о "одном большом объекте". После этого вы можете копаться в профилировщиках, например, Mission Control для JDK7u40 и выше или jProfiler, оба отлично работают.