如何检查 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 编译此文件。