Java ConculrentMarksweep мусорный сборщик не удаляет весь мусор

StackOverflow https://stackoverflow.com/questions/3873635

Вопрос

Краткая форма: сборщик мусора CMS, кажется, не может собрать постоянно растущее количество мусора; В конце концов, наш JVM заполняется, а приложение становится не отвечает. Принуждение GC через внешний инструмент (JConsole или jmap -histo:live) очищает его один раз.

Обновление: проблема, по-видимому, связана с плагином JTOP для JConsole; Если мы не запустим jconsole, или запустите его без плагина Jтопа, поведение уходит.

(Технические примечания: мы запускаем Sun JDK 1.6.0_07, 32-разряд, на поле Linux 2.6.9. Обновление версии JDK не является обязательным вариантом, если нет неизбежной, основной причины. Кроме того, наша система не подключен к доступной интернету машины, поэтому скриншоты jconsole и т. Д. Не вариант.)

В настоящее время мы работаем наш JVM со следующими флагами:

-server -Xms3072m -Xmx3072m -XX:NewSize=512m -XX:MaxNewSize=512m 
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled 
-XX:CMSInitiatingOccupancyFraction=70 
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 
-XX:+DisableExplicitGC

Наблюдая за графиком памяти в JConsole, есть полный GC, который проходит каждые ~ 15 минут или около того, в течение первых нескольких часов продолжительности жизни нашего приложения; После каждого полного GC все еще используются все еще и больше памяти. Через несколько часов система попадает в устойчивое состояние, где в старом Rece CMS приблизительно 2 ГБ памяти.

Что звучит как классическая утечка памяти, за исключением того, что если мы используем любой инструмент, который заставляет полный GC (ударяя кнопку «собирать мусор» в JConsole или работает jmap -histo:live, И т. Д.) Старый ген внезапно упал на ~ 500 МБ, и наше приложение снова отдается в течение следующих нескольких часов (в течение которого продолжается тот же шаблон - после каждого полного GC, все больше и больше старого поколения заполнены.)

Одно следует примечание: в jconsole, сообщаемое CONCURRENTMARMSWEEP GC Count будет оставаться в 0, пока не принудим GC с JConsole / jmap / etc.

С использованием jmap -histo а также jmap -histo:live В последовательности я могу определить, что видимо необъяснимые объекты состоят из:

  • несколько миллионов HashMapS и массивы HashMap$Entry (в соотношении 1: 1)
  • несколько миллионов VectorS и объектные массивы (1: 1 соотношение и примерно так же, как количество хэсмапов)
  • несколько миллионов HashSet, Hashtable, а также com.sun.jmx.remote.util.OrderClassLoaderS, а также массивы Hashtable$Entry (примерно столько же каждая; около половины как у хехмамок и векторов)

Существуют некоторые выдержки из вывода GC ниже; Моя интерпретация из них кажется, что CMS GC становится прерванным, не отказуясь до Stop-The World GC. Я как-то ошибочно истолковывать этот выход? Есть ли что-то, что бы заставить это?

Во время обычного времени выполнения блоки выходных блоков CMS GC выглядят так:

36301.827: [GC [1 CMS-initial-mark: 1856321K(2621330K)] 1879456K(3093312K), 1.7634200 secs] [Times: user=0.17 sys=0.00, real=0.18 secs]
36303.638: [CMS-concurrent-mark-start]
36314.903: [CMS-concurrent-mark: 7.804/11.264 secs] [Times: user=2.13 sys=0.06, real=1.13 secs]
36314.903: [CMS-concurrent-preclean-start]
36314.963: [CMS-concurrent-preclean: 0.037/0.060 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
36314.963: [CMS-concurrent-abortable-preclean-start]
36315.195: [GC 36315.195: [ParNew: 428092K->40832K(471872K), 1.1705760 secs] 2284414K->1897153K(3093312K), 1.1710560 secs] [Times: user=0.13 sys=0.02, real=0.12 secs]
CMS: abort preclean due to time 36320.059: [CMS-concurrent-abortable-preclean: 0.844/5.095 secs] [Times: user=0.74 sys=0.05, real=0.51 secs]
36320.062: [GC[YG occupancy: 146166 K (471872 K)]36320.062: [Rescan (parallel), 1.54078550 secs]36321.603: [weak refs processing, 0.0042640 secs] [1 CMS-remark: 1856321K(2621440K)] 2002488K(3093312K), 1.5456150 secs] [Times: user=0.18 sys=0.03, real=0.15 secs]
36321.608: [CMS-concurrent-sweep-start]
36324.650: [CMS-concurrent-sweep: 2.686/3.042 secs] [Times: uesr=0.66 sys=0.02, real=0.30 secs]
36324.651: [CMS-concurrent-reset-start]
36324.700: [CMS-concurrent-reset: 0.050/0.050 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

вот и все; Следующая строка будет следующим gc parnew.

Когда мы заставляем GC с помощью JMAP -Histo: Live, мы вместо этого получаем:

48004.088: [CMS-concurrent-mark: 8.012/8.647 secs] [Times: user=1.15 sys=0.02, real=0.87 secs]
(concurrent mode interrupted)

Содержит ~ 125 строк формы ниже: (некоторые генерируемыеMethodaccessor, некоторые генерируемые целесообразныеСтроинизационные конструктивные ресурсы, некоторые генерируемыеConstructoraccessor и т. Д.

[Unloading class sun.reflect.GeneratedMethodAccessor3]

с последующим:

: 1911295K->562232K(2621440K), 15.6886180 secs] 2366440K->562232K(3093312K), [CMS Perm: 52729K->51864K(65536K)], 15.6892270 secs] [Times: user=1.55 sys=0.01, real=1.57 secs]

Заранее спасибо!

Это было полезно?

Решение

com.sun.jmx.remote.UTIL.OrderClassAssLoader Используется в удаленном слое для JMX и быстрый обзор кода предполагает, что они созданы как часть процесса Unmarshalling для удаленных запросов внутри JVM. Срок службы этих классов будет напрямую связан с жизнью того, что было неуместно, что было немархаллировано таким, что когда-то больше нет никаких ссылок на то, что может быть выпущена классная загрузка.

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

Я думаю, возможно, есть ошибка в реализации JMX (кажется, вряд ли в сравнительно актуальном JVM) или, возможно, у вас есть некоторые пользовательские MBeans или используют некоторые пользовательские инструменты JMX, которые вызывают проблему. Но в конечном итоге я подозреваю, что загрузка, вероятно, является красной сельди, и проблема лежит в другом месте (сломанный GC или какая-то другая утечка).

Другие советы

Технические примечания: Мы запускаем Sun JDK 1.6.0_07, 32-битный, на коробке Linux 2.6.9. Обновление версии JDK не является обязательным вариантом, если нет неизбежной, основной причины.

Несколько новых версий Java имели обновления в CMS Collector. Примечательно 6U12, 6U14 и 6U18.

Я не эксперт с учетом GC, но я предполагаю, что предсказанные исправления в 6U14 мая исправить проблему, которую вы видите. Конечно, я мог бы сказать то же самое около 6U18 классовых разгрузочных ошибок. Как я уже сказал, я не эксперт в GC Parts.

Есть исправления для:

  • 6U10: (влияет на 6U4 +) CMS никогда не очищает референов, когда -xx: + parallelrefprocenabled
  • 6U12: CMS: Неправильное кодирование массивов преодоленных объектов во время одновременного предсплата
  • 6U12: CMS: Неправильная обработка переполнения при использовании параллельной параллельной маркировки
  • 6U14: CMS: Отказ утверждения «IS_CMS_THREAD == Тема :: Текущий () -> IS_CONCURRENTGC_THREAD ()»
  • 6U14: CMS: нужна CMSInitiatiTingPermoccupancanceFraction для Перми, разводки от CMSInitiatiTingoccupancyFraction
  • 6U14: CMS Assert: _Concurrent_Iterater_safe_limit обновление пропущено
  • 6U14: CMS: Неправильная обработка переполнения во время предслащивания списков контроля
  • 6U14: SIGSEGV или (! IS_NULL (V), «Значение OOP никогда не может быть нулевым») Утверждение при работе с CMS и Coops
  • 6U14: CMS: Livelock в CompactibleFreelistsPace :: Block_size ().
  • 6U14: заставить CMS работать с сжатым упс
  • 6U18: CMS: Dump Core с -xx: + USECompressedoops
  • 6U18: CMS: Ошибки, связанные с разгрузкой класса
  • 6U18: CMS: undedInitialcardmarks небезопасно в присутствии предсредственного положения CMS
  • 6U18: [регрессия] -xx: newratio с -xx: + UseconcmarksweepGC вызывает фатальную ошибку
  • 6U20: Марки карты могут быть отложены слишком длинные

В дополнение к всем вышеперечисленным, 6U14 также представил Г1. Сборщик мусора, хотя он все еще в тестировании. G1 предназначен для замены CMS в Java 7.

G1 может использоваться в Java 6U14 и новее со следующими коммутаторами командной строки:

-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

Я бы начал с чего-то гораздо проще, как:

-server -Xms3072m -Xmx3072m -XX:+UseParallelOldGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 

И посмотрите, что это соответствует вашим потребностям.

Похоже, вы строите объекты, которые указывают на своих владельцев (точки в B указывает на а). Это приводит к возмещению ссылок, оставшиеся более ноль, поэтому сборщик мусора не может их очистить. Вам нужно сломать цикл, когда вы отпускаете их. Nullificing ссылка на либо B, либо B решит проблему. Это работает даже в более крупной ссылке выглядит как (A -> B -> C -> D -> A). Векторы и объектные массивы могут использоваться вашими хэсмапами.

Прерывирование удаленных погрузчиков может указывать на невозможность очистки и тесных ссылок на объекты, загруженные через JNDI или другой метод удаленного доступа.

Редактировать: Я занял второй взгляд на вашу последнюю строку. Вы можете увеличить выделение Пермь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top