Java 关于传统解释器、编译器和JIT编译器/解释器的澄清

Java 关于传统解释器、编译器和JIT编译器/解释器的澄清,java,compilation,interpreter,jit,Java,Compilation,Interpreter,Jit,我正在学习Java,下面的事情让我有点困惑。我的理解是: Java编译器→ Java编译器只是将.Java程序转换为.class文件,这意味着将我们的源代码转换为字节码(它是虚拟机(JVM)的操作码列表,使Java平台独立) Java解释器→ 仅“解释”代码,不将其转换为本机机器代码。它以命令的形式逐个执行字节码的每条指令并执行,而不管同一条指令出现多少次。这就是为什么它很慢,Java引入了JIT概念 JIT编译器→ 这也在执行时起作用。JIT编译器能够通过缓存已翻译代码块的结果来提高性能,而

我正在学习Java,下面的事情让我有点困惑。我的理解是:

  • Java编译器→ Java编译器只是将
    .Java
    程序转换为
    .class
    文件,这意味着将我们的源代码转换为字节码(它是虚拟机(JVM)的操作码列表,使Java平台独立)

  • Java解释器→ 仅“解释”代码,不将其转换为本机机器代码。它以命令的形式逐个执行字节码的每条指令并执行,而不管同一条指令出现多少次。这就是为什么它很慢,Java引入了JIT概念

  • JIT编译器→ 这也在执行时起作用。JIT编译器能够通过缓存已翻译代码块的结果来提高性能,而不是每次字节码中的每一行或操作数发生时简单地重新计算

现在我有几个问题:

  • 由于我的物理处理器只理解本机代码,如何使用JVM的解释器执行Java程序?解释器不会将字节码转换为本机代码。除非有人将机器代码放入内存,否则物理处理器将无法执行它

  • 假设解释器还以某种方式将字节码转换为本机代码,那么“带缓存的代码块执行(JIT)和逐行执行(解释器)”是区分JIT和解释器的唯一方法

  • 如果在执行时,JIT编译器将字节码转换为本机代码(用于执行程序),为什么Java不使用提前编译?在生成依赖于JVM的字节码(这反过来又使Java平台独立)之后,我们可以将其带到我们想要执行它的目标机器上,并将其转换为本机代码(创建一个
    .exe
    .out
    文件,就像C编译一样)。这是可能的,因为我们在每个系统上都有一个特定的JVM。这将比使用JIT编译快得多,因为编译和加载程序需要一些时间。它仍然是独立于平台的,只需分发字节码(在从字节码到机器码的最终翻译之前生成)

  • 最后,即使在解释器中,相当于字节码指令的机器代码也会运行,只是发生得更间接。把它想象成一架钢琴。CPU就像一架钢琴。编译器在一张纸上打孔,然后在钢琴上运行。使用翻译器基本上就是在钢琴前放置一台类似人的机器,它可以阅读乐谱并按下钢琴上的键。最后,同样的和弦发出声音,但还有一个额外的间接层次

  • 对。差不多

  • 正如您所提到的,Java被吹捧为“编译一次,在任何地方运行”。因此字节码是实现这一承诺的一个重要特性。当它到达您的计算机时,它没有被编译的原因是一个实际的原因:编译速度很慢。通常,它发生在软件开发人员的办公室。如果您启动的每个Java应用程序都是第一次编译的,那么您需要等待一段时间

    由于大多数程序不能完全运行(有些分支没有执行,有些菜单项你从来没有选择过等等),所以编译所需的部分通常会更快,因为它们是需要的。它还节省了磁盘空间,否则您的计算机上会有每个程序的两个副本


  • 也就是说,你不是第一个对此感到疑惑的人,事实上,有些人用Java编写程序,但使用编译器从中实际生成可执行文件。java(-to母语)编译器存在,它们不是普通的用例,因为当时很多人使用了便携式C或C++。

    < P>免责声明:把这些都带到一个小范围内;这太简单了

    1:你是对的,因为计算机本身不理解代码,这就是为什么需要JVM本身。让我们假设XY的意思是“添加堆栈上最上面的两个元素并推送结果”。然后,JVM将实现如下内容:

    for(byte bytecode : codeToExecute) {
        if (bytecode == XX) {
            // ...do stuff...
        } else if (bytecode == XY) {
            int a = pop();
            int b = pop();
            push(a+b);
        } else if (bytecode == XZ) {
            // ...do stuff...
        } // ... and so on for each possible instruction ...
    }
    
    JVM在计算机的本机机器代码中实现了每一条指令,并从本质上查找每个字节码块以了解如何执行它。通过对代码进行JIT,您可以通过省略此解释(即查找每个指令应该如何处理)来实现较大的加速。这一点,以及优化

    2:JIT并没有真正运行代码;一切仍然在JVM中运行。基本上,JIT会在适当的时候将字节码块转换成机器码。当JVM遇到它时,它会想:“哦,嘿,这已经是机器代码了!好极了,现在我不必仔细检查它的每个字节,因为CPU可以自己理解它!我只需要将它抽出来,一切都会神奇地自行工作!”


    3:是的,以这种方式预编译代码以避免早期的解释和JITting开销。然而,这样做,你会失去一些非常有价值的东西。你看,当JVM解释代码时,它还保存关于一切的统计信息。然后,当它对代码进行JIT时,它知道使用不同部分的频率,允许它在重要的地方对代码进行优化,以牺牲稀有部分为代价加快普通部分的速度,从而获得总体性能提升。

    1.你的第一个类比让我摸不着头脑。2.如果它们几乎相同,那么JVM不必在JIT代码后进行任何解释?3.虽然传统的代码编译速度很慢(比JIT慢),但编译后,只有一次是可执行的