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

183

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

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

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

Богатый
источник

Ответы:

219

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

Для Java 5-7:

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

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

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

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

Аарон Дигулла
источник
17
Согласно stackoverflow.com/a/3720052/2541 для того, CMSClassUnloadingEnabledчтобы иметь какое-либо влияние, UseConcMarkSweepGCтакже должен быть установлен
Сэм Хаслер
1
Не уверен, как это влияет на идею использования UseConcatSweepGC, но, похоже, недавно в CMSClassUnloadingEnabled была исправлена ​​ошибка. Это отмечено как исправлено здесь: bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325
Билл Росмус
3
@ Кевин: Да, определенно. См в нижней части groovy.codehaus.org/Running : «Groovy создает классы динамически, но по умолчанию Java VM не GC в PermGen Если вы используете Java 6 или более поздней версии, добавить -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCНеобходимо , чтобы включить CMSClassUnloadingEnabled
Аарон Дигулла
1
Хорошая статья об использовании UseConcMarkSweepGC и CMSClassUnloadingEnabled вместе. blog.redfin.com/devblog/2012/06/…
Виктор
1
больше не действителен для 1.8: blogs.oracle.com/poonam/…
mt.uulu
35

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

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

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


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

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

Стивен С
источник
24

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

Установка -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

Лукас Эдер
источник
+1 за обмен реальным опытом. У нас также была эта проблема на Torquebox, где сервер генерировал огромное количество классов из-за процессов компиляции JRuby.
Нуреттин
7
Также обратите внимание, что -XX:+CMSPermGenSweepingEnabledне рекомендуется в пользу-XX:+CMSClassUnloadingEnabled
Nurettin
3
Реальным решением этой проблемы является создание порта один раз и его повторное использование. Вот как JAX-WS предполагается использовать. Порт также на 100% безопасен для потоков.
rustyx
@rustyx: Можете ли вы подтвердить это утверждение какой-нибудь авторитетной ссылкой? Я всегда очень настороженно относился к повторному использованию прокси-серверов и заглушек веб-служб ... Например, см. Заявление об отказе от Apache CXF . Или этот вопрос
Лукас Эдер
1
@rukavitsya: Как я уже сказал в своем ответе. Каждый раз, когда я вызывал вышеуказанную логику, создавался новый прокси
Лукас Эдер