Как увидеть JIT-скомпилированный код в JVM?
Есть ли какой-нибудь способ увидеть нативный код, созданный JIT в JVM?
7 ответов
Предполагая, что вы используете виртуальную виртуальную машину Sun Hotspot (то есть, предоставленную Oracle на java.com), вы можете добавить флаг
-XX:+PrintOptoAssembly
при запуске вашего кода. Это распечатает оптимизированный код, сгенерированный компилятором JIT, а остальное пропустит.
Если вы хотите увидеть весь байт-код, включая неоптимизированные части, добавьте
-XX:CompileThreshold=#
когда вы запускаете свой код.
Вы можете прочитать больше об этой команде и функциональности JIT в целом здесь.
Общее использование
Как объясняется другими ответами, вы можете работать со следующими параметрами JVM:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
Фильтр по определенному методу
Вы также можете фильтровать определенный метод со следующим синтаксисом:
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod
Заметки:
- вам может потребоваться поместить второй аргумент в кавычки в зависимости от ОС и т. д.
- если метод встроен, вы можете пропустить некоторые оптимизации
Как: установить необходимые библиотеки в Windows
Если вы используете Windows, эта страница содержит инструкции по сборке и установке hsdis-amd64.dll
а также hsdis-i386.dll
которые необходимы, чтобы заставить его работать. Мы копируем ниже и расширяем содержание этой страницы * для справки:
Где взять готовые двоичные файлы
Вы можете скачать готовые двоичные файлы для Windows из проекта fcml
Как построить hsdis-amd64.dll
а также hsdis-i386.dll
в Windows
Эта версия руководства была подготовлена для 64-битной Windows 8.1 с использованием 64-битного Cygwin и создания hsdis-amd64.dll
Установите Cygwin. На
Select Packages
добавьте следующие пакеты (развернувDevel
категорию, затем нажмите один раз на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. - Загрузите исходный код OpenJDK, перейдя в репозиторий JDK 8 Updates, выбрав тег, соответствующий вашей установленной версии JRE, и нажав bz2. Извлеките каталог 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-подобной средой, make-файл hsdis не может распознать его как таковой.- Сборка не удастся с сообщениями
./chew: No such file or directory
а такжеgcc: command not found
, редактировать<Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefile
в текстовом редакторе, таком как Wordpad или Notepad++, чтобы изменитьSUBDIRS = doc po
(строка 342, если используется binutils 2.25) дляSUBDIRS = po
, Повторите предыдущую команду.
Теперь DLL можно установить, скопировав ее из hsdis\build\Linux-amd64
или же hsdis\build\Linux-i586
к вашей JRE bin\server
или же bin\client
каталог. Вы можете найти все такие каталоги в вашей системе, выполнив поиск java.dll
,
Дополнительный совет: если вы предпочитаете синтаксис Intel ASM AT&T, укажите -XX:PrintAssemblyOptions=intel
наряду с любыми другими опциями PrintAssembly, которые вы используете.
* страница лицензии Creative Commons
Вам нужен плагин hsdis для использования PrintAssembly
, Удобный выбор - плагин hsdis на основе библиотеки FCML.
Он может быть скомпилирован для UNIX-подобных систем, а в Windows вы можете использовать готовые библиотеки, доступные в разделе загрузки FCML на Sourceforge:
Чтобы установить в Windows:
- Извлеките dll (его можно найти в hsdis-1.1.2-win32-i386.zip и hsdis-1.1.2-win32-amd64.zip).
- Скопируйте DLL туда, где существует
java.dll
(используйте поиск Windows). В моей системе я нашел его в двух местах: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 и смещения в виде десятичных значений.
mpad = XX Заполнение мнемонической части инструкции.
cpad = XX Заполнение для машинного кода.
seg Показывает регистры сегментов по умолчанию.
нули Показывать начальные нули в случае литералов HEX.
Синтаксис Intel является стандартным для Windows, в то время как AT&T - стандартным для GNU/Linux.
Для получения дополнительной информации см. Справочное руководство по библиотеке FCML.
Для JSM HotSpot (был Sun), даже в режимах продукта:
Некоторая сборка требуется: для этого нужен плагин.
Я считаю, что WinDbg будет полезен, если вы запускаете его на Windows-машине. Я только что пробежал одну банку.
- Затем я подключился к процессу Java через Windbg
- Проверены темы по команде ~; Было 11 тем, 0 тема была главной рабочей темой
- Переключился на 0-нить - ~ 0с
Посмотрел через unmamaged callstack от 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
Выделенные строки - это прямой запуск кода JIT на JVM.
Тогда мы можем найти адрес метода:
Java+0x2f68 это 00402f68На WinDBG:
Нажмите Вид -> Разборка.
Нажмите Редактировать -> Перейти к адресу.
Поместите 00402f68 туда
и получил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
... и так далее
Для получения дополнительной информации здесь приведен пример того, как отследить JIT-код из дампов памяти с помощью Process Explorer и WinDbg.
Другой способ увидеть машинный код и некоторые данные о производительности - использовать AMD CodeAnalyst или OProfile, которые имеют плагин Java для визуализации выполнения Java-кода в виде машинного кода.
Распечатайте сборку ваших горячих точек с помощью профилировщиков перфазма JMH (LinuxPerfAsmProfiler
или же WinPerfAsmProfiler
). JMH требует hsdis
библиотека, так как она опирается на PrintAssembly
,