[java] JVM에서 JIT 컴파일 된 코드를 보는 방법은 무엇입니까?

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.dllhsdis-i386.dll작동하는 데 필요한 지침 있습니다. 참조를 위해 아래를 복사하고 해당 페이지 *의 내용을 확장합니다.


미리 빌드 된 바이너리를 얻을 수있는 위치

fcml 프로젝트 에서 미리 빌드 된 Windows 용 바이너리를 다운로드 할 수 있습니다.

어떻게 구축 hsdis-amd64.dllhsdis-i386.dllWindows에서

이 버전의 가이드는 64 비트 Cygwin을 사용하고 hsdis-amd64.dll을 생성하는 Windows 8.1 64 비트에서 준비되었습니다.

  1. Cygwin을 설치하십시오 . 상기 Select Packages화면 (확대하여 다음 패키지를 추가 Devel한 후, 카테고리를 한 번 클릭하면 Skip다음 각 패키지 이름 라벨) :

    • make
    • mingw64-x86_64-gcc-core(에만 필요 hsdis-amd64.dll)
    • mingw64-i686-gcc-core(에만 필요 hsdis-i386.dll)
    • diffutils( Utils카테고리)
  2. Cygwin 터미널을 실행하십시오. 이것은 설치 프로그램이 만든 바탕 화면 또는 시작 메뉴 아이콘을 사용하여 수행 할 수 있으며 Cygwin 홈 디렉토리 ( C:\cygwin\home\<username>\또는 C:\cygwin64\home\<username>\기본적으로)를 생성합니다.

  3. 최신 GNU binutils 소스 패키지를 다운로드하고 Cygwin 홈 디렉토리에 압축을 풉니 다. 작성 당시 최신 패키지는 binutils-2.25.tar.bz2. 그러면 binutils-2.25Cygwin 홈 디렉토리에 이름이 지정된 디렉토리 (또는 최신 버전이 무엇이든)가 생성됩니다.
  4. JDK 8 업데이트 저장소 로 이동하여 설치된 JRE 버전에 해당하는 태그를 선택한 다음 bz2를 클릭 하여 OpenJDK 소스를 다운로드합니다 . hsdis 디렉토리 (에서 찾을 수 있음 src\share\tools)를 Cygwin 홈 디렉토리로 추출하십시오 .
  5. Cygwin 터미널에을 입력 cd ~/hsdis합니다.
  6. 빌드하려면 다음을 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=LinuxCygwin은 Linux와 유사한 환경이지만 hsdis makefile은이를 인식하지 못하기 때문에 필요합니다.

  7. 빌드가 실패하고 메시지 ./chew: No such file or directorygcc: command not found. <Cygwin home directory>\hsdis\build\Linux-amd64\bfd\MakefileWordpad 또는 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.