Java解释器或任何解释器的工作原理是什么?

时间:2017-05-09 13:10:32

标签: java jvm interpreter

我一直在弄清楚口译员的确切工作,搜索过并得出一些结论,只是希望能够让我更好地理解口译员的工作来纠正它。

所以我理解的是:

  1. 解释器是一种从高级转换代码的软件程序 语言到机器格式。
  2. 具体讲述java解释器,它以二进制格式获取代码 (早期由java编译器从源代码翻译成字节码)。
  3. 现在java解释器的平台是JVM,它运行在那里,所以 基本上它将产生可以由JVM运行的代码。
  4. 所以它需要字节码产生中间代码和目标机器 代码并将其提供给JVM。
  5. JVM轮流在JVM所在的OS平台上执行该代码 已实施或正在运作。
  6. 现在我仍然不清楚它们之间发生的子过程,即

    1. 口译员生成中间代码。
    2. 然后优化解释的代码。
    3. 然后生成目标代码
    4. 并最终执行。
    5. 还有一些问题:

      • 单独的解释器负责生成目标代码吗?和 执行它?
      • 并且执行是否意味着它在JVM或底层操作系统中执行?

5 个答案:

答案 0 :(得分:7)

  

解释器是一种将代码从高级语言转换为机器格式的软件程序。

没有。那是一个编译器。 interpreter是一个计算机程序,它执行直接用语言编写的指令。这与将较高级语言转换为较低语言的编译器不同。 C编译器从C转换为汇编代码,汇编程序(另一种编译器)从汇编代码转换为机器代码 - 现代C编译器执行从C到机器代码的两个步骤。

在Java中,java编译器执行代码验证并从Java源转换为字节码类文件。它还执行许多小的处理任务,如预先计算常量(如果可能),缓存字符串等。

  

现在java解释器的平台就是JVM,它运行在JVM中,所以基本上它会产生可以由JVM运行的代码。

JVM直接对字节码进行操作。 Java解释器与JVM紧密集成,它们不应该被视为单独的实体。正在发生的事情是大量的优化,其中字节码基本上是在运行中优化的。这使得称它只是一个翻译不足。见下文。

  

所以它需要字节码产生中间代码和目标机器代码并将其提供给JVM。

JVM正在进行这些翻译。

  

JVM轮流在实现或运行JVM的OS平台上执行该代码。

我宁愿说JVM使用字节码,优化的用户代码,包含java和本机代码的java库,以及OS调用来执行java应用程序。

  

现在我仍然不清楚它们之间发生的子过程,即1.解释器产生中间代码。 2.然后优化解释的代码。 3.然后生成目标代码4.最后执行。

Java编译器生成字节码。当JVM执行代码时,步骤2-4在JVM内部的运行时发生。它与C(例如)非常不同,后者由不同的实用程序运行这些单独的步骤。不要将其视为“子进程”,将其视为JVM内部的模块。

  

单独的解释器负责生成目标代码吗?并执行它?

排序。根据定义,JVM的解释器读取字节码并直接执行它。但是,在现代JVM中,解释器与Just-In-Time编译器(JIT)协同工作到generate native code on the fly,以便JVM可以更有效地执行代码。

此外,还有后处理“编译”阶段,它们在运行时分析生成的代码,以便通过内联常用代码块和其他机制来优化本机代码。这就是为什么JVM加载在启动时如此高的原因。它不仅加载在jar和类文件中,而且它实际上是在运行cc -O3

  

并且执行是否意味着它在JVM或底层操作系统中执行?

虽然我们讨论了执行代码的JVM,但这在技术上并不正确。一旦将字节码转换为本机代码,JVM和Java应用程序的执行就由CPU和其他硬件架构完成。

操作系统是完成所有流程和资源管理的基础,因此程序可以有效地共享硬件并高效执行。操作系统还为应用程序提供API,以便轻松访问磁盘,网络,内存以及其他硬件和资源。

答案 1 :(得分:6)

  

1)解释器是一种将代码从高级语言转换为机器格式的软件程序。

不正确的。解释器是运行以某种语言表达的程序的程序,该程序不是计算机的本机机器代码。

可能这个过程中的一个步骤,其中源语言被解析并转换为中间语言,但这不是解释器的基本要求。在Java的情况下,字节码语言已经设计,因此无需解析或使用不同的中间语言。

  

2)具体讲述java解释器,它以二进制格式获取代码(之前由java编译器从源代码翻译成字节码)。

正确。 “二进制格式”是Java字节码。

  

3)现在java解释器的平台是JVM,它运行在JVM中,所以基本上它会生成可以由JVM运行的代码。

不正确的。字节码解释器是 JVM的一部分。解释器不在JVM上运行。字节码解释器不会产生任何东西。它只是运行字节码。

  

4)所以它需要字节码产生中间代码和目标机器代码并将其提供给JVM。

不正确的。

  

5)JVM轮流在实现或运行JVM的OS平台上执行该代码。

不正确的。

真实的故事是:

  • JVM有许多组件。
  • 一个组件是字节码解释器。它几乎直接执行字节码 1 。您可以将解释器视为指令集为字节码的抽象计算机的模拟器。
  • 第二个组件是JIT编译器。这会将字节码转换为目标机器的本机代码,以便目标硬件可以执行它。

1 - 典型的字节码解释器可以将抽象堆栈帧和对象布局映射到涉及特定于目标的大小和偏移的具体映射。但要称之为“中间代码”是一个延伸。解释器实际上只是增强字节码。

答案 2 :(得分:4)

给出一个1000英尺的视图,希望能够解决问题:

Java应用程序有两个主要步骤:编译运行时。每个过程都有不同的功能和用途。两者的主要流程概述如下:

汇编

  • 这通常由[com.sun.tools.javac][1]执行,通常在tools.jar文件中找到,传统上在$ JAVA_HOME中 - 与java.jar等相同的地方。
  • 这里的目标是将.java源文件转换为.class文件,其中包含java运行时环境的“配方”。

编译步骤:

  1. Parsing :读取文件,并删除其“边界”语法字符,例如花括号,分号和括号。这些存在告诉解析器哪个java对象将每个源组件转换为(在下一点中更多关于此)。
  2. AST创建:抽象语法树是源文件的表示方式。这是一个文字“树”数据结构,其根类为[com.sun.tools.JCTree][3]。总体思路是每个Expression和每个Statement都有一个java对象。在这个时间点,对于每个代表的实际“类型”知之甚少。在创建AST时唯一检查的是文字语法
  3. Desugar :这是for循环和其他语法糖转化为更简单的形式。语言仍然是'树'形式而不是字节码,所以这很容易发生
  4. Type checking/Inference :编译器变得复杂的地方。 Java是一种静态语言,因此编译器必须使用访问者模式遍历AST,并在提前确定所有内容的类型,并确保在运行时所有内容(好吧,差不多)将是在类型,方法签名等方面都是合法的。如果某些内容过于模糊或无效,则编译失败。
  5. 字节码:检查控制流以确保程序执行逻辑有效(没有无法访问的语句等)如果所有内容都通过了检查而没有错误,则将AST转换为字节码该计划代表。
  6. .class文件写入:此时,会写入类文件。 本质上,字节码是专用机器代码之上的一小层抽象。这使得可以移植到其他机器/ CPU结构/平台,而不必担心它们之间相对较小的差异。
  7. 运行

    • 每个计算机平台都有不同的运行时环境/虚拟机实现。 Java API是通用的,但运行时环境是完全独立的软件。
    • JRE只知道如何将类文件中的字节码转换为与目标平台兼容的机器代码,并且还针对相应平台进行了高度优化。
    • 有许多不同的运行时/虚拟机实现,但最常用的是Hotspot虚拟机。
    • 虚拟机非常复杂,可以在运行时优化代码。启动时间很慢,但它实际上是“学习”的。
    • 这是运行中的'JIT'(即时)概念 - 编译器通过检查正确的类型和语法来完成所有繁重工作,而VM只是将字节码转换并优化为机器码直播。

    也...

    • Java编译器API在JSR 199下标准化。虽然不完全属于同一个东西(无法找到确切的JLS),但许多其他语言和工具利用标准化的编译过程/ API来使用Oracle提供的高级JVM(运行时)技术,同时允许不同的语法。
      • 请参阅ScalaGroovyKotlinJythonJRuby等。所有这些都利用了Java运行时环境,因为它们翻译了不同的语法与Java编译器API兼容!它非常整洁 - 任何人都可以用他们想要的任何语法编写高性能语言,因为两者的分离。几乎每种语言都适用于JVM

答案 3 :(得分:1)

我将根据我创建DSL的经验回答。

编译C是因为您运行了源代码并将其传递给gcc并在机器代码中运行存储的程序。

解释Python是因为您通过将程序源传递给解释器来运行程序。解释器读取源文件并执行它。

Java是两者的混合,因为您将Java文件“编译”为字节码,然后调用JVM来运行它。字节码不是机器码,需要由JVM解释。 Java位于C和Python之间,因为你无法做像“eval”这样的奇特事情(在运行时像在Python中一样评估代码块或表达式)。但是,Java具有C程序无法实现的反射能力。简而言之,Java运行时设计在纯编译语言和解释语言之间的中间层中,在性能和灵活性方面给出了两个单词中最好的(也是最差的)。

但是,Python也有一个虚拟机,它有自己的字节码格式。这同样适用于Perl,Lua等。这些解释器首先将源文件转换为字节码,然后解释字节码。

我总是想知道为什么这样做是必要的,直到我为模拟DSL制作了自己的解释器。我的解释器进行词法分析(打破令牌中的源),将其转换为抽象语法树,然后通过遍历它来评估树。为了软件工程,我使用了一些设计模式,而我的代码大量使用多态。与处理模仿真实计算机体系结构的有效字节码格式相比,这非常慢。如果我创建自己的虚拟机或使用现有的虚拟机,我的模拟会更快。例如,为了评估一个长数值表达式,将它转换为类似于汇编代码的东西要比处理抽象树的一个分支更快,因为它需要调用大量的多态方法。

答案 4 :(得分:0)

有两种执行程序的方法。

  • 通过编译器:在Windows .c上,它将编程语言(如.exe)的文本解析为机器代码。然后可以独立于编译器执行此操作。

可以通过将几个.c文件编译为多个目标文件(中间产品),然后链接它们到单个应用程序或库中来完成编译。

  • 通过解释器:这将解析编程语言中的文本(例如.java),然后“立即”执行程序。

使用 java 的方法有点混合/堆叠:Java编译器javac.java编译为.class文件,并可能将{{ 1}}(或.jar.war ...)。 .class文件由用于抽象堆栈计算机的更抽象的字节代码组成。

然后,Java运行时.ear(调用JVM,Java虚拟机或字节码解释器)可以执行.class / .jar。实际上,这是Java字节码的解释器

如今,它还在运行时将字节代码(的一部分)转换为机器代码。这也称为即时编译器,用于字节码到机器码。


简而言之: -java仅创建代码; -compiler立即执行。

解释器将遍历解析的命令/高级中间代码,并使用一段代码解释每个命令。原则上间接慢。