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


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

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

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

3 174

3 ответа:

обновление этот ответ актуален для 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 навсегда. Если вы используете сервер, это означает, что у вас есть утечка памяти.

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

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

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

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

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


Аарон Digulla говорит: "занятия для всегда." Это не совсем верно, даже в чисто мир Java. Фактически, время жизни класса привязано к его загрузчику классов. Поэтому, если вы можете организовать, что загрузчик классов-это сбор мусора (и это не всегда легко сделать), классы, которые он загрузил, также будут собраны в мусор.

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

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

задание -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