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

问题描述 投票:3回答:5

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

所以我所理解的是:

  1. 解释器是一种将代码从高级语言转换为机器格式的软件程序。
  2. 特别讲述java解释器,它以二进制格式获取代码(之前由java编译器从源代码翻译成字节码)。
  3. 现在,java解释器的平台是运行它的JVM,所以基本上它将生成可以由JVM运行的代码。
  4. 所以它需要字节码产生中间代码和目标机器代码并将其提供给JVM。
  5. JVM轮流在实现或运行JVM的OS平台上执行该代码。

现在我仍然不清楚之间发生的子过程,即

  1. 解释器生成中间代码。
  2. 然后优化解释的代码。
  3. 然后生成目标代码
  4. 并最终执行。

还有一些问题:

  • 单独的解释器负责生成目标代码吗?并执行它?
  • 并且执行是否意味着它在JVM或底层操作系统中执行?
java jvm interpreter
5个回答
7
投票

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

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

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

现在,java解释器的平台是运行它的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中,解释器与即时编译器(JIT)协同工作到generate native code on the fly,以便JVM可以更有效地执行代码。

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

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

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

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


6
投票

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

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

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

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

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

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

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

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

不正确。

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

不正确。

真实的故事是这样的:

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

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


4
投票

Giving a 1000 foot view which will hopefully clear things up:

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

Compilation

  • 这通常由[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:这是循环和其他语法糖转化为更简单形式的地方。语言仍然是“树”形式而不是字节码,所以这很容易发生
  4. Type checking/Inference:编译器变得复杂的地方。 Java是一种静态语言,因此编译器必须使用访问者模式检查AST,并在提前确定所有内容的类型,并确保在运行时,就类型,方法而言,所有(几乎)都是合法的签名等。如果某些内容过于模糊或无效,则编译失败。
  5. 字节码:检查控制流以确保程序执行逻辑有效(没有无法访问的语句等)如果一切都通过了检查而没有错误,则AST被转换为程序所代表的字节码。
  6. .class文件写入:此时,类文件被写入。本质上,字节码是专用机器代码之上的一小层抽象。这使得可以移植到其他机器/ CPU结构/平台,而不必担心它们之间相对较小的差异。

Runtime

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

Also...

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

1
投票

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

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

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

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

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

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


0
投票

有两种执行程序的方法。

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

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

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

使用java,这种方法有点混合/堆叠:java编译器javac.java编译为.class文件,并且可能在.jar(或.war.ear ......)中编译。 .class文件由抽象堆栈机器的更抽象的字节代码组成。

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

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


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

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

© www.soinside.com 2019 - 2024. All rights reserved.