¿Está seguro de que desea ver el código compilado con JIT (nativo) o solo el código de bytes? Lo pregunto porque hacer esta pregunta aquí lleva a algunas dudas sobre si realmente quieres ver el código nativo ... Y, lo siento, tampoco conozco una herramienta así.
gimpf
3
Quiero ver un código nativo compilado exactamente con JIT. Por supuesto, no es algo que necesite para hacer un trabajo, más bien una especie de experimentos e investigación de cosas.
alsor.net
Desafío de marco menor: un compilador dinámico como se usa en las JVM modernas no tiene solo una versión de código compilado; puede comenzar interpretando, luego compilar un método o solo parte de él, luego potencialmente recompilarlo varias veces a medida que las clases se cargan / descargan o los patrones de uso cambian o se basan en estadísticas de rendimiento. (Creo que incluso puede descartar la versión compilada y volver a interpretar si eso parece beneficioso). Por lo tanto, es posible que no solo obtenga un código diferente en diferentes máquinas, ni siquiera para diferentes ejecuciones en la misma máquina, sino en diferentes momentos en la misma ejecución .
gidds
Respuestas:
45
Suponiendo que está utilizando Sun Hotspot JVM (es decir, la proporcionada en java.com por Oracle), puede agregar la bandera
-XX: + PrintOptoAssembly
al ejecutar su código. Esto imprimirá el código optimizado generado por el compilador JIT y omite el resto.
Si desea ver el código de bytes completo, incluidas las partes no optimizadas, agregue
-XX: CompileThreshold = #
cuando está ejecutando su código.
Puede leer más sobre este comando y la funcionalidad de JIT en general aquí .
¿Esta opción solo está presente en compilaciones de depuración o algo así? Porque mi JVM ("Java (TM) SE Runtime Environment (build 1.6.0_16-b01") no lo reconoce aunque la fuente en la web indica que esta función está disponible en Sun Java 6 y OpenJDK.
¿No debería ser (hoy en día) -XX: + PrintAssembly, al menos hoy en día? Probado en mi máquina, y coincide con lo que se dice aquí: wikis.sun.com/display/HotSpotInternals/PrintAssembly Necesita -XX: + UnlockDiagnosticVMOptions antes de esta opción y un complemento desensamblador.
Blaisorblade
@Blaisorblade Estoy obteniendo: Opción de VM incorrectamente especificada 'PrintAssembly' Error: No se pudo crear la máquina virtual Java. Error: se ha producido una excepción grave. Programa saldrá.
es posible que deba poner el segundo argumento entre comillas según el sistema operativo, etc.
si el método se inserta, podría perder algunas optimizaciones
Cómo: instalar las bibliotecas necesarias en Windows
Si está ejecutando Windows, esta página tiene instrucciones sobre cómo compilar e instalar hsdis-amd64.dlly hsdis-i386.dllcuáles son necesarios para que funcione. Copiamos a continuación y ampliamos el contenido de esa página * como referencia:
Dónde obtener binarios prediseñados
Puede descargar binarios precompilados para Windows desde el proyecto fcml
Cómo construir hsdis-amd64.dlly hsdis-i386.dllen Windows
Esta versión de la guía se preparó en Windows 8.1 de 64 bits utilizando Cygwin de 64 bits y produciendo hsdis-amd64.dll
Instale Cygwin . En la Select Packagespantalla, agregue los siguientes paquetes (expandiendo la Develcategoría y luego haciendo clic una vez en la Skipetiqueta junto al nombre de cada paquete):
make
mingw64-x86_64-gcc-core(solo se necesita para hsdis-amd64.dll)
mingw64-i686-gcc-core(solo se necesita para hsdis-i386.dll)
diffutils(en Utilscategoría)
Ejecute la Terminal Cygwin. Esto se puede hacer usando el icono del escritorio o del menú de inicio creado por el instalador, y creará su directorio de inicio de Cygwin ( C:\cygwin\home\<username>\o C:\cygwin64\home\<username>\por defecto).
Descargue el último paquete fuente de GNU binutils y extraiga su contenido en su directorio de inicio de Cygwin. En el momento de escribir este artículo, el paquete más reciente es binutils-2.25.tar.bz2. Esto debería resultar en un directorio llamado binutils-2.25(o cualquiera que sea la última versión) en su directorio de inicio de Cygwin.
Descargue la fuente OpenJDK yendo al repositorio de actualizaciones de JDK 8 , seleccionando la etiqueta correspondiente a su versión de JRE instalada y haciendo clic en bz2. Extraiga el directorio hsdis (que se encuentra en src\share\tools) a su directorio de inicio de Cygwin.
En la Terminal Cygwin, ingrese cd ~/hsdis.
Para construir hsdis-amd64.dll, ingrese
make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Para construir hsdis-i386.dll, ingrese
make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
En cualquier caso, reemplácelo 2.25con la versión de binutils que descargó. OS=Linuxes necesario porque, aunque Cygwin es un entorno similar a Linux, el archivo MAKE hsdis no lo reconoce como tal.
La compilación fallará con mensajes ./chew: No such file or directoryy gcc: command not found. Edite <Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefileen un editor de texto como Wordpad o Notepad ++ para cambiar SUBDIRS = doc po(línea 342, si usa binutils 2.25) a SUBDIRS = po. Vuelva a ejecutar el comando anterior.
La DLL ahora se puede instalar copiándola desde hsdis\build\Linux-amd64o hsdis\build\Linux-i586hacia su directorio bin\servero JRE bin\client. Puede encontrar todos estos directorios en su sistema buscando java.dll.
-XX:PrintAssemblyOptions=intelConsejo adicional : si prefiere la sintaxis Intel ASM a AT&T, especifique junto con cualquier otra opción de PrintAssembly que utilice.
@AshwinJayaprakash ¿Dónde se supone que debo colocar estos archivos en Mac OS?
Koray Tugay
@KorayTugay los puso/usr/lib/
Jean-François Savard
Actualicé la respuesta copiando de la última versión de la página vinculada, pero esto destaca la razón por la que generalmente vinculamos recursos externos en lugar de copiarlos textualmente.
Aleksandr Dubinsky
@AleksandrDubinsky Gracias por la actualización. He copiado a propósito: si ese sitio se baja mi respuesta seguirá siendo autónomo ...
assylias
29
Necesita un complemento hsdis para usar PrintAssembly. Una opción conveniente es el complemento hsdis basado en la biblioteca FCML.
Se puede compilar para sistemas similares a UNIX y en Windows puede usar bibliotecas preconstruidas disponibles en la sección de descarga de FCML en Sourceforge:
Para instalar en Windows:
Extraiga el dll (se puede encontrar en hsdis-1.1.2-win32-i386.zip y hsdis-1.1.2-win32-amd64.zip).
Copie el dll donde sea que exista java.dll(use la búsqueda de Windows). En mi sistema, lo encontré en dos ubicaciones:
code Imprime el código de máquina antes del mnemónico. intel Utilice la sintaxis de Intel. gas Usa la sintaxis del ensamblador de AT&T (compatible con ensamblador GNU). dec Imprime IMM y desplazamiento como valores decimales. mpad = XX Relleno para la parte nemotécnica de la instrucción. cpad = XX Relleno para el código máquina. seg Muestra los registros de segmento predeterminados. ceros Muestra ceros a la izquierda en caso de literales HEX.
La sintaxis de Intel es predeterminada en el caso de Windows, mientras que la de AT&T es predeterminada para GNU / Linux.
Gracias por arreglar lib. También funciona muy bien en Linux. Estoy borrando mis comentarios anteriores para mantener el desorden bajo control.
Aleksandr Dubinsky
En Linux, después de instalar libhsdis.so y hacer un enlace suave a hsdis-amd64.so, ejecuto el comando java, prmpts no puede encontrar hsdis-amd64.so. Reinicio y luego vuelvo a ejecutar Java, está bien. ¿Cómo evitar el reinicio para que el enlace suave funcione instantáneamente? ¿cerrar sesión?
gfan
2
Solo una pequeña adición: en algunas distribuciones de Linux, puede simplemente instalar un paquete, por ejemplo en Ubuntu: apt-get install libhsdis0-fcml( askubuntu.com/a/991166/489909 ). Puede que no sea necesario construirlo usted mismo.
David Georg Reichelt
8
Para HotSpot (antes Sun) JVM, incluso en modos de producto:
Las líneas resaltadas son código JIT-ed de ejecución directa en JVM.
Luego podemos buscar la dirección del método: java + 0x2f68 es 00402f68
En WinDBG: haga clic en Ver -> Desmontaje. Haga clic en Editar -> Ir a dirección. Ponga 00402f68 allí
y obtuve
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 ... y así sucesivamente
Para obtener información adicional, aquí está el ejemplo de cómo rastrear el código JIT-ed de los volcados de memoria utilizando el explorador de procesos y WinDbg.
Otra forma de ver el código de máquina y algunos datos de rendimiento es utilizar CodeAnalyst u OProfile de AMD, que tienen un complemento de Java para visualizar la ejecución de código Java como código de máquina.
Imprima el ensamblaje de sus hotspots con los perfiladores perfasm de JMH ( LinuxPerfAsmProfilero WinPerfAsmProfiler). JMH requiere la hsdisbiblioteca, ya que se basa en PrintAssembly.
Respuestas:
Suponiendo que está utilizando Sun Hotspot JVM (es decir, la proporcionada en java.com por Oracle), puede agregar la bandera
al ejecutar su código. Esto imprimirá el código optimizado generado por el compilador JIT y omite el resto.
Si desea ver el código de bytes completo, incluidas las partes no optimizadas, agregue
cuando está ejecutando su código.
Puede leer más sobre este comando y la funcionalidad de JIT en general aquí .
fuente
Uso general
Como se explica en otras respuestas, puede ejecutar con las siguientes opciones de JVM:
Filtrar por un método específico
También puede filtrar por un método específico con la siguiente sintaxis:
Notas:
Cómo: instalar las bibliotecas necesarias en Windows
Si está ejecutando Windows, esta página tiene instrucciones sobre cómo compilar e instalar
hsdis-amd64.dll
yhsdis-i386.dll
cuáles son necesarios para que funcione. Copiamos a continuación y ampliamos el contenido de esa página * como referencia:Dónde obtener binarios prediseñados
Puede descargar binarios precompilados para Windows desde el proyecto fcml
Cómo construir
hsdis-amd64.dll
yhsdis-i386.dll
en WindowsEsta versión de la guía se preparó en Windows 8.1 de 64 bits utilizando Cygwin de 64 bits y produciendo hsdis-amd64.dll
Instale Cygwin . En la
Select Packages
pantalla, agregue los siguientes paquetes (expandiendo laDevel
categoría y luego haciendo clic una vez en laSkip
etiqueta junto al nombre de cada paquete):make
mingw64-x86_64-gcc-core
(solo se necesita parahsdis-amd64.dll
)mingw64-i686-gcc-core
(solo se necesita parahsdis-i386.dll
)diffutils
(enUtils
categoría)Ejecute la Terminal Cygwin. Esto se puede hacer usando el icono del escritorio o del menú de inicio creado por el instalador, y creará su directorio de inicio de Cygwin (
C:\cygwin\home\<username>\
oC:\cygwin64\home\<username>\
por defecto).binutils-2.25.tar.bz2
. Esto debería resultar en un directorio llamadobinutils-2.25
(o cualquiera que sea la última versión) en su directorio de inicio de Cygwin.src\share\tools
) a su directorio de inicio de Cygwin.cd ~/hsdis
.Para construir
hsdis-amd64.dll
, ingresemake OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Para construir
hsdis-i386.dll
, ingresemake OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
En cualquier caso, reemplácelo
2.25
con la versión de binutils que descargó.OS=Linux
es necesario porque, aunque Cygwin es un entorno similar a Linux, el archivo MAKE hsdis no lo reconoce como tal../chew: No such file or directory
ygcc: command not found
. Edite<Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefile
en un editor de texto como Wordpad o Notepad ++ para cambiarSUBDIRS = doc po
(línea 342, si usa binutils 2.25) aSUBDIRS = po
. Vuelva a ejecutar el comando anterior.La DLL ahora se puede instalar copiándola desde
hsdis\build\Linux-amd64
ohsdis\build\Linux-i586
hacia su directoriobin\server
o JREbin\client
. Puede encontrar todos estos directorios en su sistema buscandojava.dll
.-XX:PrintAssemblyOptions=intel
Consejo adicional : si prefiere la sintaxis Intel ASM a AT&T, especifique junto con cualquier otra opción de PrintAssembly que utilice.* la licencia de la página es Creative Commons
fuente
/usr/lib/
Necesita un complemento hsdis para usar
PrintAssembly
. Una opción conveniente es el complemento hsdis basado en la biblioteca FCML.Se puede compilar para sistemas similares a UNIX y en Windows puede usar bibliotecas preconstruidas disponibles en la sección de descarga de FCML en Sourceforge:
Para instalar en Windows:
java.dll
(use la búsqueda de Windows). En mi sistema, lo encontré en dos ubicaciones:C:\Program Files\Java\jre1.8.0_45\bin\server
C:\Program Files\Java\jdk1.8.0_45\jre\bin\server
Para instalar en 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
Cómo ejecutarlo:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation -XX:PrintAssemblyOptions=intel,mpad=10,cpad=10,code -jar fcml-test.jar
Parámetros de configuración adicionales:
code Imprime el código de máquina antes del mnemónico.
intel Utilice la sintaxis de Intel.
gas Usa la sintaxis del ensamblador de AT&T (compatible con ensamblador GNU).
dec Imprime IMM y desplazamiento como valores decimales.
mpad = XX Relleno para la parte nemotécnica de la instrucción.
cpad = XX Relleno para el código máquina.
seg Muestra los registros de segmento predeterminados.
ceros Muestra ceros a la izquierda en caso de literales HEX.
La sintaxis de Intel es predeterminada en el caso de Windows, mientras que la de AT&T es predeterminada para GNU / Linux.
Para obtener más detalles, consulte el Manual de referencia de la biblioteca FCML
fuente
apt-get install libhsdis0-fcml
( askubuntu.com/a/991166/489909 ). Puede que no sea necesario construirlo usted mismo.Para HotSpot (antes Sun) JVM, incluso en modos de producto:
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
Se requiere algo de ensamblaje: necesita un complemento.
fuente
Creo que WinDbg sería útil si lo está ejecutando en una máquina con Windows. Acabo de ejecutar un frasco.
Miró a través de la pila de llamadas no manipulada por kb había:
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
Las líneas resaltadas son código JIT-ed de ejecución directa en JVM.
Luego podemos buscar la dirección del método:
java + 0x2f68 es 00402f68
En WinDBG:
haga clic en Ver -> Desmontaje.
Haga clic en Editar -> Ir a dirección.
Ponga 00402f68 allí
y obtuve
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
... y así sucesivamente
Para obtener información adicional, aquí está el ejemplo de cómo rastrear el código JIT-ed de los volcados de memoria utilizando el explorador de procesos y WinDbg.
fuente
Otra forma de ver el código de máquina y algunos datos de rendimiento es utilizar CodeAnalyst u OProfile de AMD, que tienen un complemento de Java para visualizar la ejecución de código Java como código de máquina.
fuente
Imprima el ensamblaje de sus hotspots con los perfiladores perfasm de JMH (
LinuxPerfAsmProfiler
oWinPerfAsmProfiler
). JMH requiere lahsdis
biblioteca, ya que se basa enPrintAssembly
.fuente