JVM에서 JIT가 생성하는 네이티브 코드를 볼 수있는 방법이 있습니까?
답변
Sun Hotspot JVM (즉, Oracle이 java.com에서 제공 한 것)을 사용하고 있다고 가정하면 플래그를 추가 할 수 있습니다.
-XX : + PrintOptoAssembly
코드를 실행할 때. 이렇게하면 JIT 컴파일러에서 생성 된 최적화 된 코드가 출력되고 나머지는 제외됩니다.
최적화되지 않은 부분을 포함하여 전체 바이트 코드를 보려면 다음을 추가하십시오.
-XX : CompileThreshold = #
코드를 실행할 때.
이 명령과 JIT의 일반적인 기능에 대한 자세한 내용은 여기 에서 읽을 수 있습니다 .
답변
일반적인 사용법
다른 답변에서 설명한 것처럼 다음 JVM 옵션으로 실행할 수 있습니다.
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
특정 방법으로 필터링
다음 구문을 사용하여 특정 메서드를 필터링 할 수도 있습니다.
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod
메모:
- OS 등에 따라 두 번째 인수를 따옴표 안에 넣어야 할 수도 있습니다.
- 방법이 인라인되면 일부 최적화를 놓칠 수 있습니다.
방법 : Windows에 필요한 라이브러리 설치
Windows를 실행중인 경우이 페이지 에는 빌드 및 설치 방법 hsdis-amd64.dll
과 hsdis-i386.dll
작동하는 데 필요한 지침 이 있습니다. 참조를 위해 아래를 복사하고 해당 페이지 *의 내용을 확장합니다.
미리 빌드 된 바이너리를 얻을 수있는 위치
fcml 프로젝트 에서 미리 빌드 된 Windows 용 바이너리를 다운로드 할 수 있습니다.
어떻게 구축 hsdis-amd64.dll
및 hsdis-i386.dll
Windows에서
이 버전의 가이드는 64 비트 Cygwin을 사용하고 hsdis-amd64.dll을 생성하는 Windows 8.1 64 비트에서 준비되었습니다.
-
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 홈 디렉토리에 이름이 지정된 디렉토리 (또는 최신 버전이 무엇이든)가 생성됩니다. - JDK 8 업데이트 저장소 로 이동하여 설치된 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
. 이전 명령을 다시 실행하십시오.
DLL은 지금부터 복사하여 설치할 수 있습니다 hsdis\build\Linux-amd64
또는 hsdis\build\Linux-i586
귀하의 JRE의에 bin\server
또는 bin\client
디렉토리. 를 검색하여 시스템에서 이러한 모든 디렉토리를 찾을 수 있습니다 java.dll
.
보너스 팁 : AT & T보다 Intel ASM 구문을 선호하는 경우 사용 -XX:PrintAssemblyOptions=intel
하는 다른 PrintAssembly 옵션과 함께 지정 하십시오.
* 페이지 라이센스는 크리에이티브 커먼즈입니다.
답변
를 사용하려면 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 검색 사용). 내 시스템에서 두 위치에서 찾았습니다.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
추가 구성 매개 변수 :
코드 니모닉 앞에 기계어 코드를 인쇄합니다.
intel Intel 구문을 사용합니다.
gas AT & T 어셈블러 구문을 사용합니다 (GNU 어셈블러 호환 가능).
dec IMM 및 변위를 10 진수 값으로 인쇄합니다.
mpad = XX 명령어의 니모닉 부분에 대한 패딩입니다.
cpad = XX 기계 코드의 패딩입니다.
seg 기본 세그먼트 레지스터를 표시합니다.
0 HEX 리터럴의 경우 선행 0을 표시합니다.
Intel 구문은 Windows의 경우 기본 구문이고 AT & T 구문은 GNU / Linux의 기본 구문입니다.
자세한 내용은 FCML 라이브러리 참조 매뉴얼을 참조 하십시오.
답변
제품 모드에서도 HotSpot (이전 Sun) JVM의 경우 :
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
필요한 어셈블리 : 플러그인이 필요합니다.
답변
Windows 시스템에서 실행하는 경우 WinDbg가 도움이 될 것이라고 생각합니다. 나는 단지 하나의 병을 실행했습니다.
- 그런 다음 Windbg를 통해 Java 프로세스에 연결했습니다.
- ~ 명령으로 스레드를 검사했습니다 . 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 자바 + 0x3a13
0008fee4 004087b8 자바 + 0x2f68
0008ffc0 7c816fd7 자바 + 0x87b8
0008fff0 00000000 KERNEL32! BaseProcessStart + 인 0x23
강조 표시된 줄은 JVM에서 직접 실행되는 JIT 코드입니다.
-
그런 다음 메소드 주소를 찾을 수 있습니다.
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
… 등
여기에 추가 정보는 프로세스 탐색기 및 WinDbg를 사용하여 메모리 덤프에서 JIT 코드를 추적하는 방법 의 예 입니다.
답변
기계 코드와 일부 성능 데이터를 보는 또 다른 방법은 Java 코드를 기계 코드로 실행하는 것을 시각화하는 Java 플러그인이있는 AMD의 CodeAnalyst 또는 OProfile을 사용하는 것입니다.
답변
JMH의 perfasm 프로파일 러 ( LinuxPerfAsmProfiler
또는 WinPerfAsmProfiler
)로 핫스팟 어셈블리를 인쇄합니다 . JMH은 필요하지 hsdis
가에 의존하기 때문에 라이브러리를 PrintAssembly
.