Что на самом деле делает флаг JVM CMSClassUnloadingEnabled?
Я не могу на всю жизнь найти определение того, что действительно делает флаг Java CMSClassUnloadingEnabled
, за исключением некоторых очень нечетких определений высокого уровня, таких как "избавляется от ваших проблем PermGen" (который он не поддерживает, btw).
Я просмотрел сайт Sun/Oracle и даже список опций фактически не говорит, что он делает.
Основываясь на имени флага, я предполагаю, что CMS Garbage Collector по умолчанию не разгружает классы, и этот флаг включает его, но я не могу быть уверен.
Ответы
Ответ 1
Обновление. Этот ответ относится к Java 5-7, у Java 8 это исправлено: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos перейдите в mt.uulu
Для Java 5-7:
Стандартный взгляд Oracle/Sun VM на мир: Классы навсегда. Поэтому, когда они загружены, они остаются в памяти, даже если никто больше не заботится. Обычно это не проблема, так как у вас нет такого количества чисто "настраиваемых" классов (= используется один раз для настройки, а затем никогда больше). Поэтому, даже если они занимают 1 МБ, кто заботится.
Но в последнее время у нас есть такие языки, как Groovy, которые определяют классы во время выполнения. Каждый раз, когда вы запускаете script, создается один (или более) новый класс, и они остаются навсегда в PermGen. Если вы используете сервер, это означает, что у вас есть утечка памяти.
Если вы включите CMSClassUnloadingEnabled
, GC также развернет PermGen и удалит классы, которые больше не используются.
[EDIT] Вам также нужно включить UseConcMarkSweepGC
(благодаря Sam Hasler). См. Этот ответ: fooobar.com/questions/5192/...
Ответ 2
Согласно сообщению в блоге Самый полный список -XX-параметров для Java JVM, он определяет, включена ли разгрузка классов под мусором CMS коллектор. По умолчанию используется false
. Существует другая опция ClassUnloading
, которая по умолчанию true
, которая (предположительно) влияет на других сборщиков мусора.
Идея состоит в том, что если GC обнаруживает, что ранее загруженный класс больше не используется нигде в JVM, он может вернуть память, используемую для хранения байт-кода классов и/или собственного кода.
Настройка CMSClassUnloadingEnabled может помочь с вашей проблемой permgen, если вы в настоящее время используете сборщик CMS. Но есть вероятность, что вы не используете CMS или у вас есть подлинная утечка памяти, связанная с загрузкой класса. В последнем случае ваш класс никогда не появится в GC, который не будет использоваться... и поэтому никогда не будет выгружен.
Аарон Дигулла говорит, что "занятия навсегда". Это не совсем верно, даже в чисто Java-мире. Фактически, время жизни класса привязано к его загрузчику классов. Поэтому, если вы можете организовать загрузку класса загрузчика (и это не всегда легко сделать), то классы, которые он загрузил, также будут собраны в мусор.
Фактически, это то, что происходит, когда вы делаете горячую передислокацию webapp. (Или, по крайней мере, то, что должно произойти, если вы можете избежать проблем, которые приводят к утечке хранилища в пергеном.)
Ответ 3
Пример, где это полезно:
Настройка -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