46

Java アプリケーション (Tomcat で実行されるサービス) の JRE を Java 7 から Java 8 に切り替えたjava.lang.OutOfMemoryError: Metaspace後、トラフィック量が多い状態で数日間実行した後、確認できるようになりました。

ヒープの使用は問題ありませんでした。パフォーマンス テスト中に同じコード フローが実行された後、メタスペースがジャンプします。

メタスペース メモリの問題の考えられる原因は何ですか?

現在の設定は次のとおりです。

-server -Xms8g -Xmx8g -XX:MaxMetaspaceSize=3200m  -XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC -XX:MaxGCPauseMillis=1000 
-XX:+DisableExplicitGC -XX:+PrintGCDetails 
-XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=7 -XX:NewSize=5004m 
-XX:MaxNewSize=5004m -XX:MaxTenuringThreshold=12 
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintFlagsFinal  
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution 
-XX:+PrintGCCause -XX:+PrintAdaptiveSizePolicy 
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 -XX:GCLogFileSize=200M 

また、アプリケーションはリフレクションを多用しています。また、カスタム クラス ローダーを使用します。それらはすべてJava 7で正常に機能していました。

4

2 に答える 2

38

一定期間にわたって同じリクエスト (一連のリクエスト) で問題を作成できると思います。MaxMetaspaceSize を定義しておくのは良いことです。そうしないと、アプリは拡張するまでネイティブ メモリを使用します。しかし、私は次の手順から始めます:

  1. サーバーに複数回送信したときに、JVM にロードされたクラスの数が同じ要求に対して増加し続けるかどうかを確認します。はいの場合、メタスペースにロードされたクラスの成長を引き起こす動的クラスを作成している可能性があります。ロードされたクラスの数を確認する方法は、visualvm を使用して JMX を使用してサーバーに接続するか、ローカルで実行してシミュレートできます。local の手順について説明しますが、JMX をリモート接続する場合は、JVM パラメータに以下を追加してアプリケーションを起動し、ポート 9999 で -XX:+UnlockDiagnosticVMOptions を使用してリモート接続する必要があります。
   -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -XX:+UnlockDiagnosticVMOptions

visualvm (jvisualvm) を JVM に接続したら、[モニター] をクリックして、読み込まれたクラスの数を確認します。そこでは、ヒープとメタスペースを監視できます。しかし、メタスペースを綿密に監視するために他のツールを追加します。

  1. また、jvm に接続したら、ヒープ スナップショットを取得し、OQL を使用してロードされたクラスを確認することもできます。そのため、ヒープ ダンプを取得する前に、サーバーへのリクエストを停止して、進行中のリクエスト/実行中のコードとそれに関連するオブジェクトをキャッチしないようにしますが、必須ではありません。したがって、同じ一連のリクエストを複数回実行した後、visualvm 内の「モニター」スペースで、右上の「ヒープ ダンプ」をクリックします。次に、スナップショットを開いてロードすると、OQL コンソールのオプションが表示されます。 permgen 分析の下の右下のパネルにいくつかの定義済みの OQL クエリが表示されます.「classloader loaded class histogram」という名前のクエリを実行すると、各クラスローダーによってロードされたクラスの数が表示されると思います.それを使用して、どのクラスローダーを見つけることができますか?クラスを読み込んでいます。

select map(sort(map(heap.objects('java.lang.ClassLoader'), '{loader: it, count: it.classes.elementCount }'), 'lhs.count < rhs.count'), 'toHtml (それ) + "
"')

しかし、上記の「classloader loaded class」という名前のクエリは遅くなり、各クラスローダーによってロードされたクラスが実際に表示されます。

select { loader: cl,
             classes: filter(map(cl.classes.elementData, 'it'), 'it != null') }
    from instanceof java.lang.ClassLoader cl
  1. 次に、メタスペース領域の成長を追跡してみます。ここで、jconsole と、Java が持つ新しい機能である jmc (Java ミッション コントロール) を使用します。jconsole を使用して jvm (ローカルまたはリモート) に接続し、接続したら [メモリ] タブに移動して、メタスペースとコード キャッシュ、および圧縮されたクラス スペースが必要な非ヒープの成長を監視できます。そして今接続する

jmc

VM に接続するには、接続したら、右上にある JMC の [診断コマンド] をクリックします。UnlockDiagnosticVMOptions を有効にしているため、GC.class_stats を実行できます。すべての列を表示してcsvで印刷して実行することをお勧めします。したがって、コマンドは次のようになります。

GC.class_stats -all=true -csv=true

次に、さまざまな期間のクラス統計を比較し、どのクラスが問題を引き起こしているか (メタスペースの成長)、またはどのクラスがメタスペースに関連情報 (メソッド/メソッド データ) を持っているかを調べることができます。収集されたcsv出力を分析する方法:まあ、そのcsvを取得して、データベースまたは他の場所の2つの同様のテーブル(csvを表す)にロードして、SQLまたはSQLを実行できるGC.class_stats csv出力を比較します他の分析ツール。これにより、メタスペースで正確に成長しているものをよりよく理解できます。GC クラスの統計には、次の列があります。

Index,Super,InstSize,InstCount,InstBytes,Mirror,KlassBytes,K_secondary_supers,VTab,ITab,OopMap,IK_methods,IK_method_ordering,IK_default_methods,IK_default_vtable_indices,IK_local_interfaces,IK_transitive_interfaces,IK_fields,IK_inner_classes,IK_signers,class_annotations,class_type_annotations,fields_annotations,fields_type_annotations,methods_annotations, Methods_parameter_annotations,methods_type_annotations,methods_default_annotations,annotations,Cp,CpTags,CpCache,CpOperands,CpRefMap,CpAll,MethodCount,MethodBytes,ConstMethod,MethodData,StackMap,Bytecodes,MethodAll,ROAll,RWAll,Total,ClassName,ClassLoader

それが役に立てば幸い。また、1.7でリークが発生しない場合、バグはJava 8にある可能性があります。

また、いずれかがクラスローダーへの参照を保持している場合、クラスはメタスペースからアンロードされません。あなたのクラスローダーが GC されるはずで、誰もあなたのクラスローダーへの参照を保持すべきではないことがわかっている場合は、visualvm のヒープダンプに戻り、クラスローダーインスタンスをクリックして右クリックし、「最も近い GC ルート」を見つけてください。クラスローダーへの参照を保持しているあなた。

于 2016-03-29T20:42:03.490 に答える