Möchten Sie wirklich den JIT-kompilierten (nativen) Code oder nur den Byte-Code sehen? Ich frage, weil das Stellen dieser Frage hier zu einigen Zweifeln führt, wenn Sie wirklich nativen Code sehen möchten ... Und leider kenne ich ein solches Tool auch nicht.
Gimpf
3
Ich möchte exakten JIT-kompilierten nativen Code sehen. Natürlich ist es nicht etwas, was ich tun muss, um meine Arbeit zu erledigen, sondern eine Art Experiment und Untersuchung von Dingen.
alsor.net
Kleine Frame-Herausforderung: Ein dynamischer Compiler, wie er in modernen JVMs verwendet wird, verfügt nicht nur über eine Version des kompilierten Codes. Es beginnt möglicherweise mit der Interpretation, kompiliert dann eine Methode oder nur einen Teil davon und kompiliert sie möglicherweise mehrmals neu, wenn Klassen geladen / entladen werden oder sich die Verwendungsmuster ändern oder auf Leistungsstatistiken basieren. (Ich denke, es kann sogar die kompilierte Version verwerfen und zum Interpretieren zurückkehren, wenn dies vorteilhaft erscheint.) Sie erhalten also möglicherweise nicht nur unterschiedlichen Code auf verschiedenen Computern, auch nicht für unterschiedliche Läufe auf demselben Computer, sondern zu unterschiedlichen Zeiten im selben Lauf .
gidds
Antworten:
45
Angenommen, Sie verwenden die Sun Hotspot-JVM (dh die von Oracle auf java.com bereitgestellte ), können Sie das Flag hinzufügen
-XX: + PrintOptoAssembly
wenn Sie Ihren Code ausführen. Dadurch wird der vom JIT-Compiler generierte optimierte Code ausgedruckt und der Rest weggelassen.
Wenn Sie den gesamten Bytecode einschließlich der nicht optimierten Teile anzeigen möchten, fügen Sie hinzu
-XX: CompileThreshold = #
wenn Sie Ihren Code ausführen.
Weitere Informationen zu diesem Befehl und der Funktionalität von JIT im Allgemeinen finden Sie hier .
Ist diese Option nur in Debug-Builds oder so vorhanden? Da meine JVM ("Java (TM) SE-Laufzeitumgebung (Build 1.6.0_16-b01")) sie nicht erkennt, obwohl die Quelle im Web angibt, dass diese Funktion in Sun Java 6 und OpenJDK verfügbar ist.
Sollte das nicht (heutzutage) -XX: + PrintAssembly sein, zumindest heutzutage? Auf meinem Computer getestet und entspricht den hier genannten Informationen: wikis.sun.com/display/HotSpotInternals/PrintAssembly Vor dieser Option benötigen Sie -XX: + UnlockDiagnosticVMOptions und ein Disassembler-Plugin.
Blaisorblade
@Blaisorblade Ich erhalte: Falsch angegebene VM-Option 'PrintAssembly' Fehler: Die Java Virtual Machine konnte nicht erstellt werden. Fehler: Eine schwerwiegende Ausnahme ist aufgetreten. Das Programm wird geschlossen.
Je nach Betriebssystem usw. müssen Sie möglicherweise das zweite Argument in Anführungszeichen setzen.
Wenn die Methode inline wird, können einige Optimierungen fehlen
Gewusst wie: Installieren Sie die erforderlichen Bibliotheken unter Windows
Wenn Sie Windows ausführen, finden Sie auf dieser Seite Anweisungen zum Erstellen und Installieren hsdis-amd64.dllsowie zu hsdis-i386.dllden erforderlichen Funktionen. Wir kopieren unten und erweitern den Inhalt dieser Seite * als Referenz:
Wo Sie vorgefertigte Binärdateien erhalten
Sie können vorgefertigte Binärdateien für Windows aus dem fcml- Projekt herunterladen
Wie man hsdis-amd64.dllund hsdis-i386.dllunter Windows baut
Diese Version des Handbuchs wurde unter Windows 8.1 64-Bit mit 64-Bit-Cygwin erstellt und erzeugt hsdis-amd64.dll
Installieren Sie Cygwin . Fügen Sie auf dem Select PackagesBildschirm die folgenden Pakete hinzu (indem Sie die DevelKategorie erweitern und dann einmal auf die SkipBeschriftung neben jedem Paketnamen klicken ):
make
mingw64-x86_64-gcc-core(nur benötigt für hsdis-amd64.dll)
mingw64-i686-gcc-core(nur benötigt für hsdis-i386.dll)
diffutils(in UtilsKategorie)
Führen Sie das Cygwin-Terminal aus. Dies kann über das vom Installationsprogramm erstellte Desktop- oder Startmenüsymbol erfolgen und erstellt Ihr Cygwin-Ausgangsverzeichnis ( C:\cygwin\home\<username>\oder C:\cygwin64\home\<username>\standardmäßig).
Laden Sie das neueste GNU binutils-Quellpaket herunter und extrahieren Sie den Inhalt in Ihr Cygwin- Ausgangsverzeichnis . Zum Zeitpunkt des Schreibens ist das neueste Paket binutils-2.25.tar.bz2. Dies sollte zu einem Verzeichnis mit dem Namen binutils-2.25(oder der neuesten Version) in Ihrem Cygwin-Ausgangsverzeichnis führen.
Laden Sie die OpenJDK-Quelle herunter , indem Sie das Repository für JDK 8-Updates aufrufen , das Tag auswählen, das Ihrer installierten JRE-Version entspricht, und auf bz2 klicken. Extrahieren Sie das Verzeichnis hsdis (gefunden in src\share\tools) in Ihr Cygwin- Ausgangsverzeichnis .
Geben Sie im Cygwin Terminal ein cd ~/hsdis.
Geben Sie zum Erstellen hsdis-amd64.dllein
make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Geben Sie zum Erstellen hsdis-i386.dllein
make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Ersetzen 2.25Sie in beiden Fällen die heruntergeladene binutils-Version. OS=Linuxist notwendig, da Cygwin zwar eine Linux-ähnliche Umgebung ist, das hsdis-Makefile es jedoch nicht als solches erkennt.
Der Build schlägt mit Nachrichten ./chew: No such file or directoryund fehl gcc: command not found. Bearbeiten Sie <Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefilein einem Texteditor wie Wordpad oder Notepad ++, um dies zu ändern SUBDIRS = doc po(Zeile 342, wenn Sie binutils 2.25 verwenden) SUBDIRS = po. Führen Sie den vorherigen Befehl erneut aus.
Die DLL kann jetzt installiert werden, indem Sie sie von hsdis\build\Linux-amd64oder hsdis\build\Linux-i586in Ihre JREs bin\serveroder Ihr bin\clientVerzeichnis kopieren . Sie können alle diese Verzeichnisse auf Ihrem System finden, indem Sie nach suchen java.dll.
Bonus-Tipp: Wenn Sie die Intel ASM-Syntax AT & T vorziehen, geben Sie diese zusammen -XX:PrintAssemblyOptions=intelmit anderen von Ihnen verwendeten PrintAssembly-Optionen an.
@AshwinJayaprakash Wo soll ich diese Dateien in Mac OS ablegen?
Koray Tugay
@ KorayTugay legte sie in/usr/lib/
Jean-François Savard
Ich habe die Antwort durch Kopieren von der neuesten Version der verlinkten Seite aktualisiert, aber dies unterstreicht den Grund, warum wir im Allgemeinen auf externe Ressourcen verlinken, anstatt sie wörtlich zu kopieren.
Aleksandr Dubinsky
@AleksandrDubinsky Danke für das Update. Ich habe es absichtlich kopiert: Wenn diese Seite heruntergefahren wird, ist meine Antwort immer noch in sich geschlossen ...
Assylias
29
Sie benötigen ein hsdis-Plugin, um es zu verwenden PrintAssembly. Eine bequeme Wahl ist das auf der FCML-Bibliothek basierende hsdis-Plugin.
Es kann für UNIX-ähnliche Systeme kompiliert werden und unter Windows können Sie vorgefertigte Bibliotheken verwenden, die im FCML- Download- Bereich von Sourceforge verfügbar sind :
So installieren Sie unter Windows:
Extrahieren Sie die DLL (sie befindet sich in hsdis-1.1.2-win32-i386.zip und hsdis-1.1.2-win32-amd64.zip).
Kopieren Sie die DLL an einen beliebigen Ort java.dll(verwenden Sie die Windows-Suche). Auf meinem System habe ich es an zwei Stellen gefunden:
Code Druckmaschinencode vor der Mnemonik. Intel Verwenden Sie die Intel-Syntax. gas Verwenden Sie die AT & T-Assembler-Syntax (GNU-Assembler-kompatibel). dec Druckt IMM und Verschiebung als Dezimalwerte. mpad = XX Auffüllen für den mnemonischen Teil der Anweisung. cpad = XX Auffüllen des Maschinencodes. seg Zeigt die Standardsegmentregister an. Nullen HEX-Literalen werden führende Nullen angezeigt.
Die Intel-Syntax ist bei Windows eine Standardsyntax, während die AT & T-Syntax für GNU / Linux eine Standardsyntax ist.
Danke, dass du die Bibliothek repariert hast. Es funktioniert auch unter Linux hervorragend. Ich lösche meine alten Kommentare, um die Unordnung gering zu halten.
Aleksandr Dubinsky
Unter Linux, nachdem ich die Datei libhsdis.so installiert und einen Softlink zu hsdis-amd64.so erstellt habe, führe ich den Befehl java aus. Prmpts kann hsdis-amd64.so nicht finden. Ich starte neu und führe dann Java erneut aus, es ist in Ordnung. Wie vermeide ich einen Neustart, damit der Softlink sofort funktioniert? Ausloggen?
Gfan
2
Nur eine kleine Ergänzung: Auf einigen Linux-Distributionen können Sie einfach ein Paket installieren, zum Beispiel in Ubuntu: apt-get install libhsdis0-fcml( askubuntu.com/a/991166/489909 ). Dies selbst zu erstellen ist möglicherweise nicht erforderlich.
David Georg Reichelt
8
Für die HotSpot (war Sun) JVM auch in Produktmodi:
Hervorgehobene Zeilen führen direkt JIT-Code auf JVM aus.
Dann können wir nach der Methodenadresse suchen: Java + 0x2f68 ist 00402f68
In WinDBG: Klicken Sie auf Ansicht -> Demontage. Klicken Sie auf Bearbeiten -> Gehe zu Adresse. Setzen Sie 00402f68 dort
und bekam
00402f68 55 push ebp
00402f69 8bec mov ebp, esp
00402f6b 81ec80020000 sub esp, 280h
00402f71 53 push ebx
00402f72 56 push esi
00402f73 57 push edi ... und so weiter
Weitere Informationen finden Sie im Beispiel zum Zurückverfolgen von JIT-ed-Code aus Speicherabbildern mithilfe von Process Explorer und WinDbg.
Eine andere Möglichkeit, Maschinencode und einige Leistungsdaten anzuzeigen, ist die Verwendung von CodeDnalyst oder OProfile von AMD, die über ein Java-Plugin verfügen, um die Ausführung von Java-Code als Maschinencode zu visualisieren.
Drucken Sie die Baugruppe Ihrer Hotspots mit den Perfasm-Profilern ( LinuxPerfAsmProfileroder WinPerfAsmProfiler) von JMH . JMH benötigt die hsdisBibliothek, da sie darauf angewiesen ist PrintAssembly.
Antworten:
Angenommen, Sie verwenden die Sun Hotspot-JVM (dh die von Oracle auf java.com bereitgestellte ), können Sie das Flag hinzufügen
wenn Sie Ihren Code ausführen. Dadurch wird der vom JIT-Compiler generierte optimierte Code ausgedruckt und der Rest weggelassen.
Wenn Sie den gesamten Bytecode einschließlich der nicht optimierten Teile anzeigen möchten, fügen Sie hinzu
wenn Sie Ihren Code ausführen.
Weitere Informationen zu diesem Befehl und der Funktionalität von JIT im Allgemeinen finden Sie hier .
quelle
Allgemeine Verwendung
Wie in anderen Antworten erläutert, können Sie mit den folgenden JVM-Optionen ausgeführt werden:
Filtern Sie nach einer bestimmten Methode
Sie können auch nach einer bestimmten Methode mit der folgenden Syntax filtern:
Anmerkungen:
Gewusst wie: Installieren Sie die erforderlichen Bibliotheken unter Windows
Wenn Sie Windows ausführen, finden Sie auf dieser Seite Anweisungen zum Erstellen und Installieren
hsdis-amd64.dll
sowie zuhsdis-i386.dll
den erforderlichen Funktionen. Wir kopieren unten und erweitern den Inhalt dieser Seite * als Referenz:Wo Sie vorgefertigte Binärdateien erhalten
Sie können vorgefertigte Binärdateien für Windows aus dem fcml- Projekt herunterladen
Wie man
hsdis-amd64.dll
undhsdis-i386.dll
unter Windows bautDiese Version des Handbuchs wurde unter Windows 8.1 64-Bit mit 64-Bit-Cygwin erstellt und erzeugt hsdis-amd64.dll
Installieren Sie Cygwin . Fügen Sie auf dem
Select Packages
Bildschirm die folgenden Pakete hinzu (indem Sie dieDevel
Kategorie erweitern und dann einmal auf dieSkip
Beschriftung neben jedem Paketnamen klicken ):make
mingw64-x86_64-gcc-core
(nur benötigt fürhsdis-amd64.dll
)mingw64-i686-gcc-core
(nur benötigt fürhsdis-i386.dll
)diffutils
(inUtils
Kategorie)Führen Sie das Cygwin-Terminal aus. Dies kann über das vom Installationsprogramm erstellte Desktop- oder Startmenüsymbol erfolgen und erstellt Ihr Cygwin-Ausgangsverzeichnis (
C:\cygwin\home\<username>\
oderC:\cygwin64\home\<username>\
standardmäßig).binutils-2.25.tar.bz2
. Dies sollte zu einem Verzeichnis mit dem Namenbinutils-2.25
(oder der neuesten Version) in Ihrem Cygwin-Ausgangsverzeichnis führen.src\share\tools
) in Ihr Cygwin- Ausgangsverzeichnis .cd ~/hsdis
.Geben Sie zum Erstellen
hsdis-amd64.dll
einmake OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Geben Sie zum Erstellen
hsdis-i386.dll
einmake OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Ersetzen
2.25
Sie in beiden Fällen die heruntergeladene binutils-Version.OS=Linux
ist notwendig, da Cygwin zwar eine Linux-ähnliche Umgebung ist, das hsdis-Makefile es jedoch nicht als solches erkennt../chew: No such file or directory
und fehlgcc: command not found
. Bearbeiten Sie<Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefile
in einem Texteditor wie Wordpad oder Notepad ++, um dies zu ändernSUBDIRS = doc po
(Zeile 342, wenn Sie binutils 2.25 verwenden)SUBDIRS = po
. Führen Sie den vorherigen Befehl erneut aus.Die DLL kann jetzt installiert werden, indem Sie sie von
hsdis\build\Linux-amd64
oderhsdis\build\Linux-i586
in Ihre JREsbin\server
oder Ihrbin\client
Verzeichnis kopieren . Sie können alle diese Verzeichnisse auf Ihrem System finden, indem Sie nach suchenjava.dll
.Bonus-Tipp: Wenn Sie die Intel ASM-Syntax AT & T vorziehen, geben Sie diese zusammen
-XX:PrintAssemblyOptions=intel
mit anderen von Ihnen verwendeten PrintAssembly-Optionen an.* Seitenlizenz ist Creative Commons
quelle
/usr/lib/
Sie benötigen ein hsdis-Plugin, um es zu verwenden
PrintAssembly
. Eine bequeme Wahl ist das auf der FCML-Bibliothek basierende hsdis-Plugin.Es kann für UNIX-ähnliche Systeme kompiliert werden und unter Windows können Sie vorgefertigte Bibliotheken verwenden, die im FCML- Download- Bereich von Sourceforge verfügbar sind :
So installieren Sie unter Windows:
java.dll
(verwenden Sie die Windows-Suche). Auf meinem System habe ich es an zwei Stellen gefunden:C:\Program Files\Java\jre1.8.0_45\bin\server
C:\Program Files\Java\jdk1.8.0_45\jre\bin\server
So installieren Sie unter 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
/usr/lib/jvm/java-8-oracle
Wie man es ausführt:
Zusätzliche Konfigurationsparameter:
Code Druckmaschinencode vor der Mnemonik.
Intel Verwenden Sie die Intel-Syntax.
gas Verwenden Sie die AT & T-Assembler-Syntax (GNU-Assembler-kompatibel).
dec Druckt IMM und Verschiebung als Dezimalwerte.
mpad = XX Auffüllen für den mnemonischen Teil der Anweisung.
cpad = XX Auffüllen des Maschinencodes.
seg Zeigt die Standardsegmentregister an.
Nullen HEX-Literalen werden führende Nullen angezeigt.
Die Intel-Syntax ist bei Windows eine Standardsyntax, während die AT & T-Syntax für GNU / Linux eine Standardsyntax ist.
Weitere Informationen finden Sie im FCML Library Reference Manual
quelle
apt-get install libhsdis0-fcml
( askubuntu.com/a/991166/489909 ). Dies selbst zu erstellen ist möglicherweise nicht erforderlich.Für die HotSpot (war Sun) JVM auch in Produktmodi:
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
Einige Montage erforderlich: Es benötigt ein Plugin.
quelle
Ich glaube, WinDbg wäre hilfreich, wenn Sie es auf einem Windows-Computer ausführen. Ich habe gerade ein Glas laufen lassen.
Durch einen nicht verwalteten Callstack von kb geschaut gab es:
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
Hervorgehobene Zeilen führen direkt JIT-Code auf JVM aus.
Dann können wir nach der Methodenadresse suchen:
Java + 0x2f68 ist 00402f68
In WinDBG:
Klicken Sie auf Ansicht -> Demontage.
Klicken Sie auf Bearbeiten -> Gehe zu Adresse.
Setzen Sie 00402f68 dort
und bekam
00402f68 55 push ebp
00402f69 8bec mov ebp, esp
00402f6b 81ec80020000 sub esp, 280h
00402f71 53 push ebx
00402f72 56 push esi
00402f73 57 push edi
... und so weiter
Weitere Informationen finden Sie im Beispiel zum Zurückverfolgen von JIT-ed-Code aus Speicherabbildern mithilfe von Process Explorer und WinDbg.
quelle
Eine andere Möglichkeit, Maschinencode und einige Leistungsdaten anzuzeigen, ist die Verwendung von CodeDnalyst oder OProfile von AMD, die über ein Java-Plugin verfügen, um die Ausführung von Java-Code als Maschinencode zu visualisieren.
quelle
Drucken Sie die Baugruppe Ihrer Hotspots mit den Perfasm-Profilern (
LinuxPerfAsmProfiler
oderWinPerfAsmProfiler
) von JMH . JMH benötigt diehsdis
Bibliothek, da sie darauf angewiesen istPrintAssembly
.quelle