web-dev-qa-db-ja.com

JVMフラグCMSClassUnloadingEnabledは実際に何をしますか?

私は一生、Java VMフラグCMSClassUnloadingEnabledが実際に行うことの定義を見つけることができません。あなたのPermGenの問題」( それはない 、btw)。

私はSun/Oracleのサイトを見ましたが、 オプションリスト でさえ実際には何を言っているのかわかりません。

フラグの名前に基づいて、CMSガベージコレクターはデフォルトでクラスをアンロードせず、このフラグがオンになっていると推測していますが、確かではありません。

180
Rich

Updateこの回答はJava 5-7に関連し、Java 8にはこれが修正されています: https://blogs.Oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace 称賛は mt.uul

Java 5-7の場合:

世界の標準的なOracle/Sun VMの外観は次のとおりです。クラスは永遠です。したがって、ロードされると、誰も気にしなくてもメモリに残ります。多くの純粋な「セットアップ」クラスがないため、これは通常は問題ありません(=セットアップに1回使用され、それ以降は使用されません)。だから彼らが1MBを占有しても、誰も気にしません。

しかし最近、Groovyのような実行時にクラスを定義する言語があります。スクリプトを実行するたびに、1つ(またはそれ以上)の新しいクラスが作成され、PermGenに永久に残ります。サーバーを実行している場合は、メモリリークがあることを意味します。

CMSClassUnloadingEnabledを有効にすると、GCもPermGenをスイープし、使用されなくなったクラスを削除します。

[編集]UseConcMarkSweepGCも有効にする必要があります( Sam Hasler のおかげです)。この回答を参照してください: https://stackoverflow.com/a/372​​0052/2541

214
Aaron Digulla

ブログ投稿 Java JVMの-XXオプションの最も完全なリスト によると、CMSガベージコレクターでクラスのアンロードが有効になっているかどうかを判断します。デフォルトはfalseです。デフォルトではClassUnloadingであるtrueという別のオプションがあり、これは(おそらく)他のガベージコレクターに影響します。

これは、以前にロードしたクラスがJVMのどこでも使用されなくなったことをGCが検出した場合、クラスのバイトコードやネイティブコードを保持するために使用したメモリを再利用できるという考え方です。

CMSClassUnloadingEnabledの設定might permgenの問題のヘルプ現在CMSコレクターを使用している場合。ただし、CMSを使用していないか、クラスローダーに関連するメモリリークが発生している可能性があります。後者の場合、クラスはGCから使用されていないように見えないため、アンロードされません。


アーロン・ディグラは「クラスは永遠だ」と言っています。純粋にJavaの世界であっても、これは厳密には真実ではありません。実際、クラスのライフタイムはクラスローダーに関連付けられています。したがって、クラスローダーをガベージコレクションするように調整できる場合(そして、それが常に簡単なことではない場合)、ロードしたクラスもガベージコレクションされます。

実際、これは、webappのホット再デプロイを行うときに発生します。 (または、permgenストレージリークの原因となる問題を回避できる場合は、少なくとも、これが発生するはずです。)

35
Stephen C

これが役立つ例:

Weblogic 10.3 JVMで-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledを設定すると、JAX-WS実装がすべてのWebサービス呼び出しに対して新しいプロキシクラスを作成し、最終的にメモリ不足エラーにつながるという問題の解決に役立ちました。

トレースするのは簡単ではありませんでした。次のコードは、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のインスタンスに委任されました。このインスタンスは、呼び出しごとにnがインクリメントされる新しい$Proxy[nnnn]クラスに再度委任されました。フラグを追加するとき、nはまだインクリメントされましたが、少なくともそれらの一時クラスはメモリから削除されました。

より一般的な注意として、これは Java.lang.reflect.Proxy を介してJavaリフレクションとプロキシを多用する場合に非常に役立ちます。

24
Lukas Eder