Що насправді робить прапор JVM CMSClassUnloadingEnabled?


183

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

Я заглянув на сайт 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. uulu

Для 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також повинен бути встановлений
Сем HASLER

1
Не впевнений, як це впливає на ідею використання UseConcatSweepGC, але, здається, нещодавно виправлена ​​помилка в CMSClassUnloadingEnabled. Це зазначається як зафіксовано тут: bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325
Білл Росмус

3
@Kevin: Так, безумовно. Див в нижній частині 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 невикористаним ... і тому ніколи не буде завантажений.


Аарон Дігулла каже, що "заняття навіки". Це не зовсім вірно, навіть у суто явському світі. Насправді, термін експлуатації класу пов'язаний з його завантажувачем. Тож якщо ви можете домовитись, що завантажувач класів збирає сміття (а це не завжди легко зробити), класи, які він завантажував, також будуть збирати сміття.

Насправді, це те, що відбувається, коли ви робите гарячу передислокацію веб-сторінки. (Або, принаймні, саме це має статися, якщо ви зможете уникнути проблем, які призводять до витоку накопичувача пермгену.)


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
Нуреттін

3
Справжнє виправлення цієї проблеми, хоча створити порт один раз і повторно використовувати його. Ось як передбачається використовувати JAX-WS. Порт також є 100% безпечним для потоків.
rustyx

@rustyx: Чи можете ви повернути цю претензію за допомогою якогось авторитетного посилання? Я завжди дуже насторожено використовував проксі-сервери та заглушки веб-служб ... Наприклад, дивіться відмови від Apache CXF . Або це питання
Лукас Едер

1
@rukavitsya: Як я вже говорив у своїй відповіді. Щоразу, коли я називав вищезгадану логіку, створювався новий проксі
Лукас Едер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.