Как увидеть JIT-скомпилированный код в JVM?
Есть ли способ увидеть, что собственный код генерируется JIT в JVM?
Ответы
Ответ 1
Предполагая, что вы используете виртуальную виртуальную машину Sun Hotspot (то есть, предоставленную Oracle на java.com), вы можете добавить флаг
-XX:+PrintOptoAssembly
при запуске вашего кода. Это распечатает оптимизированный код, сгенерированный JIT-компилятором, и оставит остальные.
Если вы хотите увидеть весь байт-код, включая неоптимизированные части, добавьте
-XX:CompileThreshold=#
когда вы запускаете свой код.
Вы можете прочитать больше об этой команде и о функциональности JIT в целом здесь.
Ответ 2
Общее использование
Как объясняется другими ответами, вы можете запускать со следующими параметрами 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
Эта версия руководства была подготовлена на Windows 8.1 64bit с использованием 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-подобная среда, 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
(строка 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
Ответ 3
Для использования PrintAssembly
вам нужен плагин hsdis. Удобный выбор - это плагин hsdis, основанный на библиотеке FCML.
Он может быть скомпилирован для UNIX-подобных систем, а в Windows вы можете использовать предварительно созданные библиотеки, доступные в разделе FCML download в 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 Заполнение машинного кода.
Сег Показывает регистры сегментов по умолчанию.
нули Показывать ведущие нули в случае литералов HEX.
Синтаксис Intel по умолчанию используется в случае Windows, тогда как AT & T является стандартным для GNU/Linux.
Подробнее см. в Справочное руководство по библиотеке FCML
Ответ 4
Для HotSpot (было Sun) JVM, даже в режимах продукта:
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
Требуется сборка: ему нужен плагин.
Ответ 5
Я считаю, что WinDbg будет полезен, если вы используете его на компьютере Windows. Я только что запустил одну банку.
- Затем я подключился к процессу Java через Windbg
- Проверенные потоки командой ~; Было 11 потоков, 0 поток был основным рабочим потоком
- Переключено на 0-нить - ~ 0s
-
Посмотрел непрофессиональный столбец на 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-ed на 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-ed из дампов памяти с помощью проводника процессов и WinDbg.
Ответ 6
Еще один способ увидеть машинный код и некоторые данные о производительности - использовать AMD CodeAnalyst или OProfile, у которых есть плагин Java, чтобы визуализировать исполняемый код Java как машинный код.
Ответ 7
Распечатайте сборку ваших горячих точек с помощью профилировщиков JMH (LinuxPerfAsmProfiler
или WinPerfAsmProfiler
). JMH требует библиотеки hsdis
, поскольку она полагается на PrintAssembly
.