Что фактически делает флаг JVM CMSClassUnloadingEnabled? - PullRequest
179 голосов
/ 26 июля 2010

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

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

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

Ответы [ 3 ]

214 голосов
/ 26 июля 2010

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

Для Java 5-7:

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

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

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

[РЕДАКТИРОВАТЬ] Вам также нужно будет включить UseConcMarkSweepGC (благодаря Сэму Хаслеру ).Смотрите этот ответ: https://stackoverflow.com/a/3720052/2541

35 голосов
/ 26 июля 2010

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

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

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


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

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

24 голосов
/ 12 ноября 2012

Пример, в котором это полезно:

Установка -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled в нашей JVM Weblogic 10.3 помогла решить проблему, когда реализация 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

...