Có cách nào để xem mã gốc do JIT tạo ra trong JVM không?
Có cách nào để xem mã gốc do JIT tạo ra trong JVM không?
Câu trả lời:
Giả sử bạn đang sử dụng Sun Hotspot JVM (tức là JVM được cung cấp trên java.com bởi Oracle), bạn có thể thêm cờ
-XX: + PrintOptoAssembly
khi chạy mã của bạn. Thao tác này sẽ in ra mã được tối ưu hóa do trình biên dịch JIT tạo ra và loại bỏ phần còn lại.
Nếu bạn muốn xem toàn bộ mã bytecode, bao gồm cả các phần chưa được tối ưu hóa, hãy thêm
-XX: CompileThreshold = #
khi bạn đang chạy mã của mình.
Bạn có thể đọc thêm về lệnh này và chức năng của JIT nói chung tại đây .
Như được giải thích bởi các câu trả lời khác, bạn có thể chạy với các tùy chọn JVM sau:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
Bạn cũng có thể lọc theo một phương pháp cụ thể với cú pháp sau:
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod
Ghi chú:
Nếu bạn đang chạy Windows, trang này có hướng dẫn về cách xây dựng và cài đặt hsdis-amd64.dll
cũng hsdis-i386.dll
như những hướng dẫn bắt buộc để làm cho nó hoạt động. Chúng tôi sao chép bên dưới và mở rộng nội dung của trang đó * để tham khảo:
Nơi lấy mã nhị phân dựng sẵn
Bạn có thể tải xuống tệp nhị phân dựng sẵn cho Windows từ dự án fcml
Cách xây dựng hsdis-amd64.dll
và hsdis-i386.dll
trên Windows
Phiên bản này của hướng dẫn được chuẩn bị trên Windows 8.1 64 bit sử dụng Cygwin 64 bit và tạo hsdis-amd64.dll
Cài đặt Cygwin . Trên Select Packages
màn hình, thêm các gói sau (bằng cách mở rộng Devel
danh mục, sau đó nhấp một lần vào Skip
nhãn bên cạnh mỗi tên gói):
make
mingw64-x86_64-gcc-core
(chỉ cần thiết cho hsdis-amd64.dll
)mingw64-i686-gcc-core
(chỉ cần thiết cho hsdis-i386.dll
)diffutils
(trong Utils
danh mục)Chạy Cygwin Terminal. Điều này có thể được thực hiện bằng cách sử dụng biểu tượng Desktop hoặc Start Menu được tạo bởi trình cài đặt và sẽ tạo thư mục chính Cygwin của bạn ( C:\cygwin\home\<username>\
hoặc C:\cygwin64\home\<username>\
theo mặc định).
binutils-2.25.tar.bz2
. Điều này sẽ dẫn đến một thư mục có tên binutils-2.25
(hoặc bất kỳ phiên bản mới nhất nào) trong thư mục chính Cygwin của bạn.src\share\tools
) vào thư mục chính Cygwin của bạn.cd ~/hsdis
.Để xây dựng hsdis-amd64.dll
, hãy nhập
make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Để xây dựng hsdis-i386.dll
, hãy nhập
make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Trong cả hai trường hợp, hãy thay thế 2.25
bằng phiên bản binutils bạn đã tải xuống. OS=Linux
là cần thiết bởi vì, mặc dù Cygwin là một môi trường giống như Linux, nhưng hsdis makefile không nhận ra nó như vậy.
./chew: No such file or directory
và gcc: command not found
. Chỉnh sửa <Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefile
trong trình soạn thảo văn bản như Wordpad hoặc Notepad ++ để thay đổi SUBDIRS = doc po
(dòng 342, nếu sử dụng binutils 2.25) thành SUBDIRS = po
. Chạy lại lệnh trước đó.DLL hiện có thể được cài đặt bằng cách sao chép nó từ hsdis\build\Linux-amd64
hoặc hsdis\build\Linux-i586
vào thư mục bin\server
hoặc JRE của bạn bin\client
. Bạn có thể tìm thấy tất cả các thư mục như vậy trên hệ thống của mình bằng cách tìm kiếm java.dll
.
Mẹo bổ sung: nếu bạn thích cú pháp Intel ASM hơn AT&T, hãy chỉ định -XX:PrintAssemblyOptions=intel
cùng với bất kỳ tùy chọn PrintAssembly nào khác mà bạn sử dụng.
* giấy phép trang là Creative Commons
/usr/lib/
Bạn cần một plugin hsdis để sử dụng PrintAssembly
. Một lựa chọn thuận tiện là plugin hsdis dựa trên thư viện FCML.
Nó có thể được biên dịch cho các hệ thống giống UNIX và trên Windows, bạn có thể sử dụng các thư viện được tạo sẵn có sẵn trong phần tải xuống FCML trên Sourceforge:
java.dll
(sử dụng tìm kiếm của Windows). Trên hệ thống của mình, tôi tìm thấy nó ở hai vị trí:
C:\Program Files\Java\jre1.8.0_45\bin\server
C:\Program Files\Java\jdk1.8.0_45\jre\bin\server
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
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
-XX:+LogCompilation -XX:PrintAssemblyOptions=intel,mpad=10,cpad=10,code
-jar fcml-test.jar
Các thông số cấu hình bổ sung:
mã In mã máy trước khi ghi nhớ.
intel Sử dụng cú pháp Intel.
gas Sử dụng cú pháp trình hợp dịch AT&T (tương thích trình hợp dịch GNU).
dec In IMM và dịch chuyển dưới dạng giá trị thập phân.
mpad = XX Phần đệm cho phần ghi nhớ của hướng dẫn.
cpad = XX Phần đệm cho mã máy.
seg Hiển thị các đăng ký phân đoạn mặc định.
số không Hiển thị các số không ở đầu trong trường hợp chữ HEX.
Cú pháp Intel là cú pháp mặc định trong trường hợp Windows, trong khi cú pháp AT&T là cú pháp mặc định cho GNU / Linux.
Để biết thêm chi tiết, hãy xem Sổ tay Tham khảo Thư viện FCML
apt-get install libhsdis0-fcml
( askubuntu.com/a/991166/489909 ). Việc tự xây dựng cái này có thể không cần thiết.
Đối với HotSpot (là Sun) JVM, ngay cả trong các chế độ sản phẩm:
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
Yêu cầu một số lắp ráp: nó cần một plugin.
Tôi tin rằng WinDbg sẽ hữu ích nếu bạn đang chạy nó trên máy tính Windows. Tôi vừa chạy một lọ.
Nhìn qua callstack không người lái theo kb, có:
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
Các dòng được đánh dấu là mã JIT-ed đang chạy trực tiếp trên JVM.
Sau đó, chúng ta có thể tìm kiếm địa chỉ phương thức:
java + 0x2f68 là 00402f68
Trên WinDBG:
Nhấp vào View -> Disassembly.
Nhấp vào Chỉnh sửa -> Chuyển đến Địa chỉ.
Đặt 00402f68 ở đó
và có
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
... và v.v.
Để biết thêm thông tin, đây là Ví dụ về cách truy tìm lại mã JIT-ed từ các kết xuất bộ nhớ bằng cách sử dụng trình khám phá quy trình và WinDbg.
In tập hợp các điểm phát sóng của bạn bằng ( LinuxPerfAsmProfiler
hoặc WinPerfAsmProfiler
) các bộ định hình perfasm của JMH . JMH yêu cầu hsdis
thư viện vì nó dựa vào PrintAssembly
.