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


183

CMSClassUnloadingEnabled「PermGenの問題を取り除きます」などの非常にあいまいな高レベルの定義を除いて、Java VMフラグが実際に行うことの定義を一生見つけることはできません

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

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

回答:


219

更新この回答は、Java 5-7に関連している、Javaの8は、この固定がありますhttps://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace賞賛に行くメートル。うーる

Java 5-7の場合:

世界の標準的なOracle / Sun VMの外観は次のとおりです。クラスは永遠です。したがって、一度読み込まれると、誰も気にしなくてもメモリに残ります。純粋に「セットアップ」クラスはそれほど多くないので、これは通常は問題ありません(=セットアップに一度使用され、その後は二度と使用されません)。したがって、1MBを占有する場合でも、問題ありません。

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

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

[編集]有効にする必要もありますUseConcMarkSweepGCSam Haslerに感謝)。この回答を参照してください:https : //stackoverflow.com/a/372​​0052/2541


17
stackoverflow.com/a/372​​0052/2541によるとCMSClassUnloadingEnabled、影響を与えるためにUseConcMarkSweepGCも設定する必要があります
Sam Hasler

1
これがUseConcatSweepGCの使用にどのように影響するかはわかりませんが、CMSClassUnloadingEnabledで最近修正されたバグがあったようです。これは修正されたものとしてここで注記
Bill Rosmus

3
@ケビン:はい、間違いなく。以下の下部にある参照してくださいgroovy.codehaus.org/Running:「Groovyのが動的にクラスを作成しますが、デフォルトのJava VMがGC PermGenない追加、Javaの6以降を使用している場合。-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGCUseConcMarkSweepGC有効にする必要がありますCMSClassUnloadingEnabled。」
アーロンディグラ2013

1
UseConcMarkSweepGCとCMSClassUnloadingEnabledの併用に関する優れた記事。blog.redfin.com/devblog/2012/06/...
ビクター

1
もはや1.8の有効な:blogs.oracle.com/poonam/...
mt.uulu

35

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

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

CMSClassUnloadingEnabledを設定すると、可能性があなたのpermgenの問題に役立つあなたが現在CMSコレクタを使用している場合。しかし、可能性は、CMSを使用していないか、または本物のクラスローダー関連のメモリリークがあることです。後者の場合、クラスが未使用であるようにGCに表示されることはないため、アンロードされることはありません。


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

実際、これは、webappのホット再デプロイを行うときに起こります。(または、少なくとも、permgenのストレージリークにつながる問題を回避できれば、それが起こるはずです。)


24

これが役立つ例:

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledWeblogic 10.3 JVMを設定すると、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委任されており、再び、呼び出しごとに増分される新しい$Proxy[nnnn]クラスに委任されましたn。フラグを追加すると、nはまだ増加していましたが、少なくともそれらの一時クラスはメモリから削除されました。

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


実際の経験を共有するための+1。また、JRubyのコンパイルプロセスが原因でサーバーが膨大な数のクラスを生成するTorkboxにもこの問題がありました。
nurettin 2013年

7
また、これ-XX:+CMSPermGenSweepingEnabledが非推奨であることにも注意してください-XX:+CMSClassUnloadingEnabled
nurettin 2013年

3
ただし、この問題の実際の修正は、ポートを一度作成して再利用することです。これがJAX-WSの使用方法です。また、ポートは100%スレッドセーフです。
rustyx 2014

@rustyx:信頼できるリンクでその主張を裏付けることができますか?私は常にWebサービスのプロキシとスタブを再利用することに非常に警戒してきました...たとえば、Apache CXFの免責事項を参照してください。またはこの質問
Lukas Eder 2014

1
@rukavitsya:答えで言ったように。上記のロジックを呼び出すたびに、新しいプロキシが作成されました
Lukas Eder
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.