如何检查 Java 代码的汇编输出?
How do I check assembly output of Java code?
我发现这个问题为 C++ 提供了答案:
How do you get assembler output from C/C++ source in gcc?
Java 使用字节码。最相似的是 javap
,根据链接的 Oracle 文档,javap 命令反汇编一个或多个 class 文件。它的输出取决于所使用的选项。
package com.Whosebug;
class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
如果我将其编译为 Main.class
然后 运行 javap -v Main.class
我得到
Classfile /home/efrisch/workspace/Whosebug/bin/com/Whosebug/Main.class
Last modified Jun 18, 2015; size 553 bytes
MD5 checksum de4f987e783aa0f145e7245269504028
Compiled from "Main.java"
class com.Whosebug.Main
minor version: 0
major version: 52
flags: ACC_SUPER
Constant pool:
#1 = Class #2 // com/Whosebug/Main
#2 = Utf8 com/Whosebug/Main
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Methodref #3.#9 // java/lang/Object."<init>":()V
#9 = NameAndType #5:#6 // "<init>":()V
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/Whosebug/Main;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Fieldref #17.#19 // java/lang/System.out:Ljava/io/PrintStream;
#17 = Class #18 // java/lang/System
#18 = Utf8 java/lang/System
#19 = NameAndType #20:#21 // out:Ljava/io/PrintStream;
#20 = Utf8 out
#21 = Utf8 Ljava/io/PrintStream;
#22 = String #23 // Hello, World!
#23 = Utf8 Hello, World!
#24 = Methodref #25.#27 // java/io/PrintStream.println:(Ljava/lang/String;)V
#25 = Class #26 // java/io/PrintStream
#26 = Utf8 java/io/PrintStream
#27 = NameAndType #28:#29 // println:(Ljava/lang/String;)V
#28 = Utf8 println
#29 = Utf8 (Ljava/lang/String;)V
#30 = Utf8 args
#31 = Utf8 [Ljava/lang/String;
#32 = Utf8 SourceFile
#33 = Utf8 Main.java
{
com.Whosebug.Main();
descriptor: ()V
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/Whosebug/Main;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22 // String Hello, World!
5: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 5: 0
line 6: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
}
SourceFile: "Main.java"
Java 同时使用字节码和 汇编语言 机器码。这是一个两步过程。正如@elliott-frisch 指出的那样,第一步是将 Java 源代码编译为字节码。在运行时,JVM 会监视程序的哪些部分被频繁使用。如果一个方法“runs hot”,它会被编译成机器码。反过来,这本身就是一个多步骤过程,包括许多优化和用更快的代码替换快速代码。几年前,我在 BeyondJava.net 中对此进行了描述。
如果你能抽出 45 分钟,我也推荐看一下 Charles Nutter 的演讲。 "Down the rabbit hole" 很好地介绍了 Java 如何编译成汇编语言。
关于您的问题:您必须在启动应用程序的命令中添加一些参数:
javaw.exe -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly Adder
您还必须下载一个特殊的DLL 并将其存储在jre 文件夹中。另见 Chris Newlands article 如何为 OS X 编译此文件。
我发现这个问题为 C++ 提供了答案:
How do you get assembler output from C/C++ source in gcc?
Java 使用字节码。最相似的是 javap
,根据链接的 Oracle 文档,javap 命令反汇编一个或多个 class 文件。它的输出取决于所使用的选项。
package com.Whosebug;
class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
如果我将其编译为 Main.class
然后 运行 javap -v Main.class
我得到
Classfile /home/efrisch/workspace/Whosebug/bin/com/Whosebug/Main.class
Last modified Jun 18, 2015; size 553 bytes
MD5 checksum de4f987e783aa0f145e7245269504028
Compiled from "Main.java"
class com.Whosebug.Main
minor version: 0
major version: 52
flags: ACC_SUPER
Constant pool:
#1 = Class #2 // com/Whosebug/Main
#2 = Utf8 com/Whosebug/Main
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Methodref #3.#9 // java/lang/Object."<init>":()V
#9 = NameAndType #5:#6 // "<init>":()V
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/Whosebug/Main;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Fieldref #17.#19 // java/lang/System.out:Ljava/io/PrintStream;
#17 = Class #18 // java/lang/System
#18 = Utf8 java/lang/System
#19 = NameAndType #20:#21 // out:Ljava/io/PrintStream;
#20 = Utf8 out
#21 = Utf8 Ljava/io/PrintStream;
#22 = String #23 // Hello, World!
#23 = Utf8 Hello, World!
#24 = Methodref #25.#27 // java/io/PrintStream.println:(Ljava/lang/String;)V
#25 = Class #26 // java/io/PrintStream
#26 = Utf8 java/io/PrintStream
#27 = NameAndType #28:#29 // println:(Ljava/lang/String;)V
#28 = Utf8 println
#29 = Utf8 (Ljava/lang/String;)V
#30 = Utf8 args
#31 = Utf8 [Ljava/lang/String;
#32 = Utf8 SourceFile
#33 = Utf8 Main.java
{
com.Whosebug.Main();
descriptor: ()V
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/Whosebug/Main;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22 // String Hello, World!
5: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 5: 0
line 6: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
}
SourceFile: "Main.java"
Java 同时使用字节码和 汇编语言 机器码。这是一个两步过程。正如@elliott-frisch 指出的那样,第一步是将 Java 源代码编译为字节码。在运行时,JVM 会监视程序的哪些部分被频繁使用。如果一个方法“runs hot”,它会被编译成机器码。反过来,这本身就是一个多步骤过程,包括许多优化和用更快的代码替换快速代码。几年前,我在 BeyondJava.net 中对此进行了描述。
如果你能抽出 45 分钟,我也推荐看一下 Charles Nutter 的演讲。 "Down the rabbit hole" 很好地介绍了 Java 如何编译成汇编语言。
关于您的问题:您必须在启动应用程序的命令中添加一些参数:
javaw.exe -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly Adder
您还必须下载一个特殊的DLL 并将其存储在jre 文件夹中。另见 Chris Newlands article 如何为 OS X 编译此文件。