あはは、HotSpot、何してるの、やめて!





おそらく既にご存知のように、次のジョーカー会議はすぐにサンクトペテルブルクで開催されます。 JVMの動作を調査する方法についてのレポートを彼女に提供するつもりです。JVMの動作は、最初は神秘的で神秘的に思えます。 この投稿は、レポートに何を期待するかを理解する機会を提供するためのティーザーです。



問題に関する情報を突然受け取ったとします。ガベージを収集すると、 「Last Ditch Collection」「No GC」の理由表示され、インターネット検索ではわかりやすいものは得られません。 幸いなことに、HotSpotはOpenJDKからほぼ完全に組み立てられているため、少なくとも理論的には、すべての質問に対する答えをソースで直接見つけることができます。 どうしよう!





最後の溝コレクション

OpenJDKソースコードを準備して、興味のある行を探しましょう。



$ grep -irn "Last Ditch Collection" . ./src/share/vm/gc_interface/gcCause.cpp:94: return "Last ditch collection";
      
      





ファイルに移動すると、 _last_ditch_collection



への参照が_last_ditch_collection



ます。これは、ガベージコレクションの考えられるすべての理由を含むenum



要素です。 「GCなし」の目的の定数をすぐに確認すると、 _no_gc



になります。 拍手し続けます:



 $ grep -rn "GCCause::_last_ditch_collection" . ... ./src/share/vm/gc_implementation/shared/vmGCOperations.cpp:286: heap->collect_as_vm_thread(GCCause::_last_ditch_collection); ...
      
      







それはそれのようです! 呼び出しが配置されているメソッド 、特にそのコメントを読んだ後、何が起こっているかをすぐに理解できます。



どうやら、HotSpotがメタスペース(クラスなど)にあるものにスペースを割り当てることができない場合、 GCCause::_metadata_GC_threshold



という理由でガベージコレクションが最初に開始されます。 これで解決しない場合は、メタスペースを拡張しようとします。 これが役に立たない場合は、 GCCause::_last_ditch_collection



という理由で完全なガベージコレクションが開始されます。 このビルド中に、ソフト参照はクリアされます。 これでも解決しない場合、場所は本当に終わり、OOMをスローする時間です。



もっともらしいが、安定して再現することを学ぶ価値がある。 上記を信じている場合、メタスペースの積極的なポイ捨てにより、 「最後の溝の収集」という理由で少なくとも1つのアセンブリが表示されるはずです。



 ClassPool pool = ClassPool.getDefault(); for(long l = 0; l < Long.MAX_VALUE; l++) { pool.makeClass("com.example.Kitty" + l).toClass(); }
      
      





デフォルトの設定でこれを実行する場合、長時間待つ必要があります。 ただし、メタスペースのサイズを小さくして、結果をより速く取得できます。



 $ java -cp build/libs/labs-8-all.jar -XX:+PrintGCDetails -XX:MaxMetaspaceSize=10m ru.gvsmirnov.perv.labs.gc.NoGcTrigger ... [Full GC (Last ditch collection) [...] 14470K->14425K(32768K), [Metaspace: 8971K->8971K(1056768K)], 0.0481030 secs] ... Exception in thread "main" javassist.CannotCompileException: by java.lang.OutOfMemoryError: Metaspace at javassist.ClassPool.toClass(ClassPool.java:1099) ...
      
      







ほとんどの場合、「ラストディッチコレクション」の原因を持つ複数のアセンブリが表示されます。 そうでなければ、それらは役に立たず、この機能はほとんど実装されていなかったので、これは非常に期待されています。



ところで、ここではJava 9のソースに注目しましたが、最後の溝コレクションのロジックは長い間変更されていないため、心配する必要はありません。



言及する価値のある別の面白いこと:私たちは一般に、メタスペースで積極的に台無しにするコードを書く必要はありませんでした。 すべてのコード:結局のところ、JVMはクラスをロードすることも非常に喜んでいます。 java -XX:+PrintGCDetails -XX:MaxMetaspaceSize=2m X



を実行すると、最後の溝コレクションを取得してから、OOMを数回取得します。 仮想マシンには、クラスX



が存在しないことを理解する時間すらありません。



GCなし

No GCに進みましょう。 キャプテンは、HotSpotの開発者がガベージコレクションの通常の理由にほとんど名前を付けなかったと言っています。 とにかく、論理的には、少なくとも1つのガベージコレクションが発生する前にjstatを開始する時間がある場合にのみ表示されるはずです。



 $ jstat -gccause -t `jps | grep NoGc | cut -d' ' -f1` 100 Timestamp S0 S1 EOP YGC YGCT FGC FGCT GCT LGCC GCC 0.7 0.00 0.00 4.00 0.00 40.34 0 0.000 0 0.000 0.000 No GC No GC 0.8 0.00 0.00 6.00 0.00 45.82 0 0.000 0 0.000 0.000 No GC No GC 0.9 0.00 0.00 6.00 0.00 51.44 0 0.000 0 0.000 0.000 No GC No GC
      
      





または、ガベージコレクターがアクティブでないときにチェックを行う場合:



 Timestamp S0 S1 EOP YGC YGCT FGC FGCT GCT LGCC GCC 2.8 0.00 0.00 0.00 0.78 31.00 5 0.080 5 1.051 1.131 Allocation Failure No GC
      
      







したがって、別の状況で発見された場合、それはバグに違いありません。 そして、最後の溝コレクションを分析したとき、そのような奇妙な現象は観察されなかったため、つまり、すでに修正されている可能性があります。 少し楽観的に見て、適切なコミットをすべて探しましょう。



 $ hg grep --all '::_no_gc' ... src/share/vm/gc_implementation/shared/vmGCOperations.cpp:2097:+: assert(((_gc_cause != GCCause::_no_gc) && ...
      
      







うん! この問題は、2013年2月にコミット番号2097で本当に修正されたようです。 hotspot_versionファイルを見ると、問題が観察される最後のHotSpotは21.0-b01であることがわかります。 HotSpotバージョン20.45-b01の Java 6を手元に用意しました



 $ java -version java version "1.6.0_45" Java(TM) SE Runtime Environment (build 1.6.0_45-b06) Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
      
      







catの例を実行すると、すぐに次の結果が得られます。



 Timestamp S0 S1 EOP YGC YGCT FGC FGCT GCT LGCC GCC 2.7 0.00 0.00 0.00 0.78 100.00 5 0.080 5 1.051 1.131 unknown GCCause Allocation Failure 2.8 0.00 0.00 0.00 0.78 100.00 5 0.080 5 1.051 1.131 unknown GCCause Allocation Failure
      
      







これはかなり近いですが、私たちが探していたものとはまったく異なります。 ただし、パッチのより詳細な調査により、異なるガベージコレクタを使用するだけでよいことが明らかになります。 -XX:+UseG1GC



を追加すると、望ましい結果が得られます。



 Timestamp S0 S1 EOP YGC YGCT FGC FGCT GCT LGCC GCC 1.6 ? ? ? ? 96.78 ? ? ? ? ? G1 Evacuation Pause No GC 1.7 ? ? ? ? 100.00 ? ? ? ? ? No GC Permanent Generation Full 1.8 ? ? ? ? 100.00 ? ? ? ? ? No GC Permanent Generation Full 1.9 ? ? ? ? 100.00 ? ? ? ? ? No GC Permanent Generation Full 2.0 ? ? ? ? 100.00 ? ? ? ? ? No GC Permanent Generation Full
      
      







成功! ところで、疑問符がある理由とG1を使用する正確な理由に最初に答える人は、Joker Unconferenceへの招待を受け取ります;) SerCeはすでに正しい答えを出しています



あとがき

そのため、1つのツイートに基づいて、基本的なコマンドラインユーティリティを使用して、Google以外の質問に答え、HotSpotの古いバグを見つけ、上からJVMバージョンを評価でき、使用されているガベージコレクターを見つけました。



教訓は単純です。HotSpotは、ある種の神秘的なシャイタンマシンではありません。 世界には神秘的なものはまったくありませんそれは私たちの頭の中だけです。



PSこのオペラの興味深い例がある場合は、お気軽にお送りください。 レポートで分析することも、そのように分析することもできます:)



PPSロシア語を知らない招待講演者が会議に参加します。 英語でもっとレポートがあれば彼らは喜んでいるでしょう。 大多数の学生がこれにどのように関連するかを理解するために、調査を追加しました。



All Articles