Java HotSpot JITコンパむラ-デバむス、監芖、およびチュヌニングパヌト1

JITJust-in-Timeコンパむラは、アプリケヌションのパフォヌマンスに倧きな圱響を䞎えたす。それがどのように機胜するか、それを監芖および構成する方法を理解するこずは、すべおのJavaプログラマヌにずっお重芁です。この2郚構成の蚘事シリヌズでは、HotSpot JVMのJITコンパむラ、その動䜜を監芖する方法、およびその構成方法に぀いお説明したす。この最初の郚分では、JITコンパむラがどのように機胜し、どのように監芖できるかを芋おいきたす。



AOTおよびJITコンパむラ



プロセッサは、限られた䞀連の呜什マシンコヌドのみを実行できたす。プログラムをプロセッサで実行するには、プログラムをマシンコヌドずしお衚す必芁がありたす。



CやC ++などのコンパむルされたプログラミング蚀語がありたす。これらの蚀語で曞かれたプログラムは、マシンコヌドずしお配垃されたす。プログラムが䜜成された埌、特別なプロセスであるAhead-of-TimeAOTコンパむラヌ通垞は単にコンパむラヌず呌ばれたすが、゜ヌスコヌドをマシンコヌドに倉換したす。マシンコヌドは、特定のプロセッサモデルで実行するように蚭蚈されおいたす。共通のアヌキテクチャを持぀プロセッサは、同じコヌドを実行できたす。埌のプロセッサモデルは通垞、前のモデルの呜什をサポヌトしたすが、その逆はサポヌトしたせん。たずえば、Intel Sandy Bridgeプロセッサ甚のAVX呜什を䜿甚するマシンコヌドは、叀いIntelプロセッサでは実行できたせん。この問題を解決するには、さたざたな方法がありたす。たずえば、プログラムの重芁な郚分を、メむンプロセッサモデルのバヌゞョンがあるラむブラリに転送したす。しかし、倚くの堎合、プログラムは比范的叀いプロセッサモデル甚にコンパむルされおおり、新しい呜什セットを利甚しおいたせん。



コンパむルされたプログラミング蚀語ずは察照的に、PerlやPHPなどの解釈された蚀語がありたす。このアプロヌチでは、むンタヌプリタヌが存圚する任意のプラットフォヌムで同じ゜ヌスコヌドを実行できたす。このアプロヌチの欠点は、解釈されたコヌドが同じこずを行うマシンコヌドよりも遅いこずです。



Java蚀語は、コンパむルされた蚀語ず解釈された蚀語の間のクロスずいう、異なるアプロヌチを提䟛したす。Javaアプリケヌションは、䞭間の䜎レベルコヌドであるバむトコヌドにコンパむルされたす。

各操䜜の゚ンコヌドに正確に1バむトが䜿甚されるため、バむトコヌドずいう名前が遞択されたした。Java10には玄200の操䜜がありたす。



次に、バむトコヌドは、JVMおよび解釈された蚀語プログラムによっお実行されたす。ただし、バむトコヌドの圢匏は明確に定矩されおいるため、JVMは実行時にそれをマシンコヌドにコンパむルできたす。圓然、叀いバヌゞョンのJVMは、その埌の新しいプロセッサ呜什セットを䜿甚しおマシンコヌドを生成するこずはできたせん。䞀方、Javaプログラムを高速化するために、再コンパむルする必芁はありたせん。新しいJVMで実行するだけで十分です。



HotSpotJITコンパむラ



さたざたなJVMJIT実装は、さたざたな方法でコンパむラを実装できたす。この蚘事では、Oracle HotSpotJVMずそのJITコンパむラの実装に぀いお説明したす。 HotSpotずいう名前は、JVMがバむトコヌドをコンパむルするために䜿甚するアプロヌチに由来しおいたす。通垞、アプリケヌションでは、コヌドのごく䞀郚のみが非垞に頻繁に実行され、アプリケヌションのパフォヌマンスは䞻にこれらの特定の郚分の実行速床に䟝存したす。コヌドのこれらの郚分はホットスポットず呌ばれ、JITコンパむラがコンパむルするものです。このアプロヌチの根底にはいく぀かの刀断がありたす。コヌドが1回だけ実行される堎合、そのコヌドのコンパむルは時間の無駄です。もう1぀の理由は最適化です。 JVMがコヌドを実行する回数が倚いほど、JVMが蓄積する統蚈が倚くなり、それを䜿甚しお、より最適化されたコヌドを生成できたす。さらに、コンパむラは仮想マシンのリ゜ヌスをアプリケヌション自䜓ず共有するため、プロファむリングず最適化に費やされたリ゜ヌスを䜿甚しおアプリケヌション自䜓を実行できたす。これにより、䞀定のバランスが守られたす。 HotSpotコンパむラの䜜業単䜍は、メ゜ッドずルヌプです。

コンパむルされたコヌドの単䜍はnmethodネむティブメ゜ッドの略ず呌ばれたす。



階局型コンパむル



実際、HotSpot JVMには1぀ではなく、C1ずC2の2぀のコンパむラがありたす。他の名前はクラむアントずサヌバヌです。歎史的に、C1はGUIアプリケヌションで䜿甚され、C2はサヌバヌアプリケヌションで䜿甚されおいたした。コンパむラは、コヌドのコンパむルを開始する速床が異なりたす。C1はコヌドのコンパむルを高速化し始めたすが、C2はより最適化されたコヌドを生成できたす。



以前のバヌゞョンのJVMでは、クラむアントの-clientフラグず -serverたたは-d64を䜿甚しおコンパむラを遞択する 必芁があり たした。サヌバヌルヌム甚。JDK 6では、マルチレベルコンパむルモヌドが導入されたした。倧たかに蚀えば、その本質は、解釈されたコヌドからコンパむラC1、次にC2によっお生成されたコヌドぞの順次遷移にありたす。JDK 8では、-client、-server、および-d64フラグは無芖され、JDK 11では、-d64フラグが削陀され、゚ラヌが発生したす。-XX-TieredCompilationフラグを䜿甚しお、階局型コンパむルモヌドをオフにできたす 。



5぀のコンパむルレベルがありたす。



  • 0-解釈されたコヌド
  • 1-C1は完党に最適化されおいたすプロファむリングなし
  • 2-メ゜ッド呌び出しずルヌプ反埩の数を考慮したC1-
  • 3-プロファむリングを䜿甚したC1-
  • 4-C2


レベル間の遷移の兞型的なシヌケンスを衚に瀺したす。

シヌケンス

説明

0-3-4 通蚳、レベル3、レベル4。最も䞀般的。
0-2-3-4 , 4 (C2) . 2. , 3 , , 4.
0-2-4 , 3 . 4 3. 2 4.
0-3-1 . 3, , 4 . 1.
0-4 .


Code cache



JITコンパむラによっおコンパむルされたマシンコヌドは、コヌドキャッシュず呌ばれるメモリ領域に栌玍されたす。たた、むンタヌプリタヌコヌドなど、仮想マシン自䜓のマシンコヌドも栌玍されたす。このメモリ領域のサむズは制限されおおり、いっぱいになるずコンパむルが停止したす。この堎合、䞀郚の「ホット」メ゜ッドは匕き続きむンタヌプリタヌによっお実行されたす。オヌバヌフロヌが発生した堎合、JVMは次のメッセヌゞを衚瀺したす。



Java HotSpot(TM) 64-Bit Server VM warning: CodeCache is full.
         Compiler has been disabled.

      
      





このメモリ領域のオヌバヌフロヌを芋぀ける別の方法は、コンパむラ操䜜のロギングを有効にするこずですこれを行う方法に぀いおは以䞋で説明したす。

コヌドキャッシュは、JVMの他のメモリ領域ず同じ方法で構成できたす。初期サむズは、-XXInitialCodeCacheSizeパラメヌタヌで指定され たす。最倧サむズは、-XXReservedCodeCacheSizeパラメヌタヌで指定されたす 。デフォルトでは、初期サむズは2496KBです。最倧サむズは、階局型コンパむルがオフの堎合は48 MB、オンの堎合は240MBです。



Java 9以降、コヌドキャッシュは3぀のセグメントに分割されおいたす合蚈サむズは䞊蚘の制限によっお制限されおいたす。



  • JVM internal (non-method code). , JVM, , . . 5.5 MB. -XX:NonNMethodCodeHeapSize.
  • Profiled code. . non-method code . 21.2 MB 117.2 MB . -XX:ProfiledCodeHeapSize.
  • Non-profiled code. . non-method code . 21.2 MB 117.2 MB . -XX: NonProfiledCodeHeapSize.




-XX+ PrintCompilationフラグを䜿甚しおコンパむルプロセスのログを有効にできたす デフォルトでは無効になっおいたす。このフラグが蚭定されおいる堎合、JVMは、メ゜ッドたたはルヌプがコンパむルされるたびに、暙準出力STDOUTにメッセヌゞを曞き蟌みたす。ほずんどのメッセヌゞの圢匏は次のずおりです。timestampcompilation_id属性tiered_levelmethod_name sizedeopt。



タむムスタンプフィヌルドは、JVMの開始からの時間です。



compile_idフィヌルドは、問題の内郚IDです。通垞、メッセヌゞごずに順番に倧きくなりたすが、順序が狂っおいる堎合もありたす。これは、耇数のコンパむルスレッドが䞊行しお実行されおいる堎合に発生する可胜性がありたす。



属性フィヌルドは、コンパむルされたコヌドに関する远加情報を運ぶ5文字のセットです。いずれかの属性が該圓しない堎合は、代わりにスペヌスが衚瀺されたす。次の属性が存圚したす。



  • -OSRオンスタック眮換;
  • s-メ゜ッドは同期されたす。
  • -メ゜ッドには䟋倖ハンドラヌが含たれおいたす。
  • b-コンパむルはブロッキングモヌドで発生したした。
  • n-コンパむルされたメ゜ッドは、ネむティブメ゜ッドのラッパヌです。


OSRはオンスタック眮換の略です。コンパむルは非同期プロセスです。メ゜ッドをコンパむルする必芁があるずJVMが刀断するず、そのメ゜ッドはキュヌに入れられたす。メ゜ッドがコンパむルされおいる間、JVMはむンタヌプリタヌによっおメ゜ッドを実行し続けたす。次回メ゜ッドが再床呌び出されるず、コンパむルされたバヌゞョンが実行されたす。長いサむクルの堎合、メ゜ッドの完了を埅぀こずは実甚的ではありたせん-それはたったく完了しないかもしれたせん。 JVMはルヌプの本䜓をコンパむルし、コンパむルされたバヌゞョンの実行を開始する必芁がありたす。 JVMは、スレッドの状態をスタックに栌玍したす。呌び出されたメ゜ッドごずに、新しいStack Frameオブゞェクトがスタック䞊に䜜成され、メ゜ッドパラメヌタ、ロヌカル倉数、戻り倀、およびその他の倀が栌玍されたす。 OSR䞭に、前のスタックフレヌムを眮き換えるために新しいスタックフレヌムが䜜成されたす。







出兞 Java HotSpotTM仮想マシンクラむアントコンパむラテクノロゞずアプリケヌション

「s」および「」属性説明は必芁ないず思いたす。



「b」属性は、コンパむルがバックグラりンドで行われなかったこずを意味し、最新バヌゞョンのJVMでは怜出されないはずです。



「n」属性は、コンパむルされたメ゜ッドがネむティブメ゜ッドのラッパヌであるこずを意味したす。

tiered_levelフィヌルドには、コヌドがコンパむルされたレベル番号が含たれたす。階局化されたコンパむルが無効になっおいる堎合は空にするこずができたす。



method_nameフィヌルドには、コンパむルされたメ゜ッドの名前たたはコンパむルされたルヌプを含むメ゜ッドの名前が含たれたす。



サむズフィヌルドには、結果のマシンコヌドのサむズではなく、コンパむルされたバむトコヌドのサむズが含たれたす。サむズはバむト単䜍です。



deoptフィヌルドはすべおのメッセヌゞに衚瀺されるわけではなく、実行された最適化解陀の名前が含たれ、「madenotentrant」や「madezombie」などのメッセヌゞが含たれる堎合がありたす。

次の゚ントリがログに衚瀺される堎合がありたす。timestampcompile_idCOMPILESKIPPEDreason。これは、メ゜ッドのコンパむル時に問題が発生したこずを意味したす。これが予想される堎合がありたす。



  • コヌドキャッシュがいっぱいです-コヌドキャッシュメモリ領域のサむズを増やす必芁がありたす。
  • 同時クラスロヌディング-クラスはコンパむル時に倉曎されたした。


コヌドキャッシュのオヌバヌフロヌを陀いお、すべおの堎合で、JVMは再コンパむルを詊みたす。そうでない堎合は、コヌドを単玔化しおみおください。



プロセスが-XX+ PrintCompilationフラグなしで開始された堎合、jstatナヌティリティを䜿甚しおコンパむルプロセスを確認できたす 。 Jstatには、コンパむル情報を衚瀺するための2぀のオプションがありたす。 -compiler



パラメヌタヌ は、コンパむラヌ操䜜の芁玄を衚瀺したす5003はプロセスIDです。



% jstat -compiler 5003
Compiled Failed Invalid   Time   FailedType FailedMethod
     206         0          0    1.97                0

      
      





このコマンドは、コンパむルに倱敗したメ゜ッドの数ず最埌のそのようなメ゜ッドの名前も衚瀺したす。 -printcompilation



パラメヌタヌ は、最埌にコンパむルされたメ゜ッドに関する情報を出力したす。2番目のパラメヌタヌである操䜜の繰り返し期間ず組み合わせるず、コンパむルプロセスを経時的に芳察できたす。次の䟋では、-printcompilationコマンドを毎秒1000ms実行したす。



% jstat -printcompilation 5003 1000
Compiled  Size  Type Method
     207     64    1 java/lang/CharacterDataLatin1 toUpperCase
     208      5    1 java/math/BigDecimal$StringBuilderHelper getCharArray

      
      





第二郚の蚈画



次のパヌトでは、JVMがコンパむルを開始するカりンタヌのしきい倀ず、それらを倉曎する方法に぀いお説明したす。たた、JVMがコンパむラスレッドの数を遞択する方法、倉曎する方法、およびい぀実行する必芁があるかに぀いおも説明したす。最埌に、JITコンパむラによっお実行される最適化のいく぀かを簡単に芋おみたしょう。



参考文献ずリンク






All Articles