187

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

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

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

4

3 に答える 3

224

更新この回答はJava5-7に関連しており、Java 8ではこれが修正されています:https : //blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos gotomt 。 uulu

Java 5-7の場合:

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

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

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

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

于 2010-07-26T12:57:52.970 に答える
36

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

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

CMSClassUnloadingEnabled を設定すると、現在 CMS コレクターを使用している場合、 permgenの問題を解決できる場合があります。ただし、CMS を使用していないか、クラスローダに関連するメモリ リークが実際に発生している可能性があります。後者の場合、あなたのクラスは GC に未使用として表示されることはありません...したがって、アンロードされることはありません。


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

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

于 2010-07-26T13:00:18.683 に答える
24

これが役立つ例:

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再び委譲されました。フラグを追加すると、は引き続きインクリメントされますが、少なくともこれらの一時クラスはメモリから削除されました。$Proxy[nnnn]nn

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

于 2012-11-12T10:34:15.643 に答える