JVM で JIT によって生成されたネイティブ コードを確認する方法はありますか?
7 に答える
一般的な使用法
他の回答で説明されているように、次の JVM オプションで実行できます。
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
特定の方法でフィルタリングする
次の構文を使用して、特定のメソッドでフィルター処理することもできます。
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod
ノート:
- OS などによっては、2 番目の引数を引用符で囲む必要がある場合があります。
- メソッドがインライン化されると、いくつかの最適化を見逃す可能性があります
方法: Windows に必要なライブラリをインストールする
Windows を実行している場合、このページには、ビルドとインストールの方法hsdis-amd64.dll
と、hsdis-i386.dll
それを機能させるために必要な手順が記載されています。そのページ*の内容を参照用に以下にコピーして拡張します。
ビルド済みバイナリの入手先
fcmlプロジェクトから Windows 用のビルド済みバイナリをダウンロードできます。
Windowshsdis-amd64.dll
でのビルド方法hsdis-i386.dll
このバージョンのガイドは、64 ビットの Cygwin を使用して hsdis-amd64.dll を生成する Windows 8.1 64 ビットで作成されました。
Cygwin をインストールします。
Select Packages
画面で、次のパッケージを追加します (カテゴリを展開し、各パッケージ名の横にあるラベルDevel
を 1 回クリックします)。Skip
make
mingw64-x86_64-gcc-core
( にのみ必要hsdis-amd64.dll
)mingw64-i686-gcc-core
( にのみ必要hsdis-i386.dll
)diffutils
(Utils
カテゴリ内)
Cygwin ターミナルを実行します。これは、インストーラーによって作成されたデスクトップまたはスタート メニュー アイコンを使用して行うことができ、Cygwin ホーム ディレクトリ (
C:\cygwin\home\<username>\
またはC:\cygwin64\home\<username>\
デフォルト) が作成されます。- 最新の GNU binutils ソース パッケージをダウンロードし、その内容を Cygwin ホーム ディレクトリに抽出します。執筆時点での最新パッケージは
binutils-2.25.tar.bz2
. これにより、binutils-2.25
Cygwin ホーム ディレクトリに (または最新バージョンが何であれ) という名前のディレクトリが作成されます。 - JDK 8 Updates リポジトリに移動し、インストールされている JRE バージョンに対応するタグを選択し、bz2 をクリックして、OpenJDK ソースをダウンロードします。hsdis ディレクトリ (にあり
src\share\tools
ます) を Cygwin ホーム ディレクトリに抽出します。 - Cygwin ターミナルで、 と入力し
cd ~/hsdis
ます。 をビルドする
hsdis-amd64.dll
には、次のように入力します。make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
をビルドする
hsdis-i386.dll
には、次のように入力します。make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
2.25
どちらの場合も、ダウンロードした binutils バージョンに置き換えます。OS=Linux
Cygwin は Linux に似た環境ですが、hsdis makefile はそれを認識できないため、これが必要です。- ビルドはメッセージ
./chew: No such file or directory
とgcc: command not found
.<Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefile
Wordpad や Notepad++ などのテキスト エディターで編集してSUBDIRS = doc po
(binutils 2.25 を使用している場合は 342 行目) をSUBDIRS = po
. 前のコマンドを再実行します。
hsdis\build\Linux-amd64
DLL は、JRE またはディレクトリから、またはhsdis\build\Linux-i586
JREbin\server
またはディレクトリにコピーすることでインストールできますbin\client
。を検索すると、システム上のそのようなディレクトリをすべて見つけることができますjava.dll
。
おまけのヒント: AT&T よりも Intel ASM 構文を好む場合は、-XX:PrintAssemblyOptions=intel
使用する他の PrintAssembly オプションと一緒に指定してください。
※ページライセンスはクリエイティブコモンズ
Sun Hotspot JVM (つまり、 Oracle によってjava.comで提供されているもの) を使用していると仮定すると、フラグを追加できます。
-XX:+PrintOptoAssembly
コードを実行するとき。これにより、JIT コンパイラによって生成された最適化されたコードが出力され、残りは除外されます。
最適化されていない部分を含むバイトコード全体を見たい場合は、
-XX:CompileThreshold=#
コードを実行しているとき。
このコマンドと JIT の一般的な機能の詳細については、こちらを参照してください。
使用するには hsdis プラグインが必要ですPrintAssembly
。便利な選択肢は、FCML ライブラリに基づく hsdis プラグインです。
UNIX ライクなシステム用にコンパイルでき、Windows では、Sourceforge の FCMLダウンロードセクションで入手できるビルド済みのライブラリを使用できます。
Windows にインストールするには:
- dll を解凍します (hsdis-1.1.2-win32-i386.zip および hsdis-1.1.2-win32-amd64.zip にあります)。
- dll が存在する場所にコピーします
java.dll
(Windows 検索を使用します)。私のシステムでは、次の 2 つの場所で見つかりました。C:\Program Files\Java\jre1.8.0_45\bin\server
C:\Program Files\Java\jdk1.8.0_45\jre\bin\server
Linux にインストールするには:
- ソースコードをダウンロードして解凍する
cd <source code dir>
./configure && make && sudo make install
cd example/hsdis && make && sudo make install
sudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/lib/amd64/hsdis-amd64.so
sudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/jre/lib/amd64/hsdis-amd64.so
- 私のシステムでは、JDKが
/usr/lib/jvm/java-8-oracle
実行方法:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
-XX:+LogCompilation -XX:PrintAssemblyOptions=intel,mpad=10,cpad=10,code
-jar fcml-test.jar
追加の構成パラメーター:
codeニーモニックの前にマシンコードを表示します。
intel Intel 構文を使用します。
Gas AT&T アセンブラー構文 (GNU アセンブラー互換) を使用します。
dec IMM と変位を 10 進値で出力します。
mpad=XX命令のニーモニック部分のパディング。
cpad=XXマシンコードのパディング。
segデフォルトのセグメント レジスタを表示します。
zeros HEX リテラルの場合、先行ゼロを表示します。
Windows の場合は Intel 構文がデフォルトであり、GNU/Linux の場合は AT&T がデフォルトです。
Windowsマシンで実行している場合、WinDbgが役立つと思います。私はちょうど1つの瓶を走らせました。
- 次に、 Windbgを介して Java プロセスにアタッチしました
- ~コマンドで調べたスレッド。11 個のスレッドがあり、0 個のスレッドがメインのワーカー スレッドでした
- 0 スレッドに切り替え - ~0 秒
管理されていないコールスタックをkbで調べたところ、次のものがありました:
0008fba8 7c90e9c0 ntdll!KiFastSystemCallRet
0008fbac 7c8025cb ntdll!ZwWaitForSingleObject+0xc
0008fc10 7c802532 kernel32!WaitForSingleObjectEx+0xa8
0008fc24 00403a13 kernel32!WaitForSingleObject+0x12
0008fc40 00402f68 java+0x3a13
0008fee4 004087b8 java+0x2f68
0008ffc0 7c816fd7 java+0x87b8
0008fff0 00000000 kernel32!BaseProcessStart+0x23
強調表示されている行は、JVM で直接実行されている JIT コードです。
次に、メソッドアドレスを探すことができます:
java+0x2f68 は 00402f68 ですWinDBG の場合:
[表示] --> [逆アセンブリ] をクリックします。
[編集] --> [アドレスに移動] をクリックします。そこに 00402f68を
入れ て得た00402f68 55 プッシュ ebp
00402f69 8bec mov ebp,esp
00402f6b 81ec80020000 サブ esp,280h
00402f71 53 プッシュ ebx
00402f72 56 プッシュ esi
00402f73 57 プッシュ edi
...など
追加情報については、プロセス エクスプローラーと WinDbg を使用してメモリ ダンプから JIT 処理されたコードをトレース バックする方法の例を次に示します。
マシン コードと一部のパフォーマンス データを表示するもう 1 つの方法は、AMD の CodeAnalyst または OProfile を使用することです。これには、実行中の Java コードをマシン コードとして視覚化する Java プラグインが含まれています。