Что на самом деле делает флаг JVM CMSClassUnloadingEnabled?

Я не могу найти определение того, что на самом деле делает флаг Java VM CMSClassUnloadingEnabled, кроме некоторых очень нечетких высокоуровневых определений, таких как «избавление от ваших проблем с PermGen» (чего нет, кстати).

Я просмотрел сайт Sun/Oracle и даже список опций на самом деле не говорит, что он делает.

Основываясь на названии флага, я предполагаю, что сборщик мусора CMS по умолчанию не выгружает классы, и этот флаг включает его, но я не уверен.


person Rich    schedule 26.07.2010    source источник


Ответы (3)


Обновление Этот ответ актуален для Java 5-7, в Java 8 исправлено это: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-постоянноепоколение-и-метапространство Престижность перейти к mt.uulu

Для Java 5-7:

Стандартный взгляд Oracle/Sun VM на мир таков: классы вечны. Таким образом, после загрузки они остаются в памяти, даже если никому больше не нужны. Обычно это не проблема, так как у вас не так много чисто "установочных" классов (= используются один раз для установки и больше никогда). Так что даже если они занимают 1 МБ, кого это волнует.

Но в последнее время у нас появились такие языки, как Groovy, которые определяют классы во время выполнения. Каждый раз, когда вы запускаете скрипт, создается один (или несколько) новых классов, которые навсегда остаются в PermGen. Если вы используете сервер, это означает, что у вас есть утечка памяти.

Если вы включите CMSClassUnloadingEnabled, GC также зачистит PermGen и удалит классы, которые больше не используются.

[EDIT] Вам также необходимо включить UseConcMarkSweepGC (спасибо Сэму Хаслеру). См. этот ответ: https://stackoverflow.com/a/3720052/2541

person Aaron Digulla    schedule 26.07.2010
comment
Согласно stackoverflow.com/a/3720052/2541, чтобы CMSClassUnloadingEnabled имело какое-либо влияние, также необходимо установить UseConcMarkSweepGC - person Sam Hasler; 15.08.2012
comment
Не знаю, как это повлияет на идею использования UseConcatSweepGC, но похоже, что в CMSClassUnloadingEnabled недавно была исправлена ​​ошибка. Здесь отмечено как исправленное: bugs.sun.com/bugdatabase/view_bug.do ?bug_id=8000325 - person Bill Rosmus; 10.06.2013
comment
Для таких языков, как Groovy, которые динамически определяют классы, рекомендуется ли включать этот флаг для периодической очистки PermGen? - person Kevin Meredith; 17.08.2013
comment
@Кевин: Да, определенно. См. внизу groovy.codehaus.org/Running: Groovy создает классы динамически, но Java по умолчанию VM не GC PermGen. Если вы используете Java 6 или более позднюю версию, добавьте -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGC необходимо для включения CMSClassUnloadingEnabled. - person Aaron Digulla; 19.08.2013
comment
@BillR есть идеи, как интерпретировать этот отчет об ошибке? В какой версии для CMSClassUnloadingEnabled по умолчанию установлено значение true? Я не мог решить это. - person David Roussel; 18.11.2014
comment
Хорошая статья о совместном использовании UseConcMarkSweepGC и CMSClassUnloadingEnabled. blog.redfin.com/devblog/2012 /06/ - person Victor; 19.11.2014
comment
@DavidRoussel, глядя на это, я предполагаю, что это будет исправлено сейчас. - person Bill Rosmus; 19.11.2014
comment
больше не действует для версии 1.8: blogs.oracle .com/пунам/ - person mt.uulu; 23.08.2017

Согласно сообщению в блоге наиболее полный список опций -XX для Java JVM, он определяет, включена ли выгрузка классов в сборщике мусора CMS. По умолчанию false. Существует еще одна опция, называемая ClassUnloading, которая по умолчанию равна true и (предположительно) влияет на другие сборщики мусора.

Идея состоит в том, что если сборщик мусора обнаружит, что ранее загруженный класс больше нигде в JVM не используется, он может восстановить память, используемую для хранения байт-кода и/или собственного кода классов.

Параметр CMSClassUnloadingEnabled может помочь решить вашу проблему с permgen, если вы в настоящее время используете сборщик CMS. Но есть вероятность, что вы не используете CMS или у вас есть настоящая утечка памяти, связанная с загрузчиком классов. В последнем случае ваш класс никогда не будет казаться сборщику мусора неиспользуемым... и, следовательно, никогда не будет выгружен.


Аарон Дигулла говорит, что «классы вечны». Это не совсем так, даже в чисто Java-мире. На самом деле время жизни класса привязано к его загрузчику классов. Таким образом, если вы можете организовать сборку мусора для загрузчика классов (а это не всегда легко сделать), загруженные классы также будут собирать мусор.

Фактически, это то, что происходит, когда вы выполняете горячее повторное развертывание веб-приложения. (По крайней мере, это должно произойти, если вы можете избежать проблем, которые приводят к утечке хранилища permgen.)

person Stephen C    schedule 26.07.2010

Пример, где это полезно:

Установка -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled в нашей Weblogic 10.3 JVM помогла решить проблему, когда реализация JAX-WS создавала новый прокси-класс для каждого вызова веб-службы, что в конечном итоге приводило к ошибкам нехватки памяти.

Проследить было не просто. Следующий код всегда возвращал один и тот же прокси-класс для port

final MyPortType port = 
Service.create(
        getClass().getResource("/path/to.wsdl"), 
        new QName("http://www.example.com", "MyService"))
    .getPort(
        new QName("http://www.example.com", "MyPortType"), 
        MyPortType.class);

Внутри этот прокси делегируется экземпляру weblogic.wsee.jaxws.spi.ClientInstance, который снова делегируется новому классу $Proxy[nnnn], где n увеличивается при каждом вызове. При добавлении флагов n по-прежнему увеличивалось, но, по крайней мере, эти временные классы были удалены из памяти.

В более общем плане это может быть очень полезно при интенсивном использовании отражения Java и прокси через java.lang.reflect.Proxy

person Lukas Eder    schedule 12.11.2012
comment
+1 за то, что поделился реальным опытом. У нас также была эта проблема с Torquebox, где сервер генерировал огромное количество классов из-за процессов компиляции JRuby. - person nurettin; 22.03.2013
comment
также обратите внимание, что -XX:+CMSPermGenSweepingEnabled устарел в пользу -XX:+CMSClassUnloadingEnabled - person nurettin; 22.03.2013
comment
Настоящим решением этой проблемы является создание порта один раз и его повторное использование. Вот как предполагается использовать JAX-WS. Порт также на 100% безопасен для потоков. - person rustyx; 11.07.2014
comment
@rustyx: Можете ли вы подкрепить это утверждение какой-нибудь авторитетной ссылкой? Я всегда очень опасался повторного использования прокси-серверов и заглушек веб-сервисов... см. Отказ от ответственности Apache CXF. Или этот вопрос - person Lukas Eder; 11.07.2014
comment
@Lukas Eder Это просто любопытно, вы сказали: Weblogic создал новый прокси-класс для каждого вызова веб-службы, означает ли это, что если я сделаю простой get/post запрос, Weblogic создаст новый экземпляр Proxy (возможно, в данный момент он в прошлом). Правильно ли мое понимание? - person Artem; 18.01.2017
comment
@rukavitsya: Как я уже сказал в своем ответе. Каждый раз, когда я вызывал вышеуказанную логику, создавался новый прокси - person Lukas Eder; 18.01.2017
comment
@ Лукас Эдер Воспроизводится ли он сейчас? - person Artem; 18.01.2017
comment
@rukavitsya: Эй, извини, понятия не имею. Это было в 2012 году... Сейчас я работаю над другими проектами. - person Lukas Eder; 19.01.2017