首页
Preview

Java 架构

在本文中,你将学习到Java程序如何在简单的语言中编译和运行。我们可以在任何文本编辑器(记事本、Sublime Text、Atom等)中编写任何简单的Java程序,但前提是你的Java程序应该包含正确的语言语法和.java格式。

例如,我创建了一个名为FirstJavaProgram的简单Java程序,格式为.java。

现在,在我们使用Java编译器(javac)编译这个程序时,它将生成一个带有类名和.class格式的字节码文件。例如,下面的图片显示了上面Java程序的编译。

编译Java程序通过javac

在Java程序编译后,我们可以看到如下图所示的字节码生成。

在javac之前(在编译器编译程序之前)

在javac之后(编译器编译程序之后)

为什么Java是跨平台的?

我们可以看到,在Java程序编译后,会自动生成一个.class文件。现在,这个.class文件被JVM解释,并且JVM将这个.class文件转换成机器码(二进制代码)。这就是Java是平台无关的语言的原因,因为它首先生成字节码,这个字节码由JVM进一步解释,JVM是一个机器相关的程序。

现在让我们看看什么是JVM(Java虚拟机),但在理解之前,我们应该清楚地了解整个Java程序过程,如下图所示。

下面的图表示Java架构,其中每个步骤都用图形详细说明。

Java架构

Java架构概述

Java架构是一组组件,即JVM、JRE和JDK。它集成了解释和编译的过程。它定义了创建Java程序涉及的所有过程。Java架构解释了编译和执行程序的每一个步骤。

可以使用以下步骤来解释Java架构:

  • Java中存在编译和解释的过程。
  • Java编译器将Java代码转换为字节码。
  • 然后,JVM将字节码转换为机器码。
  • 机器码然后由机器执行。

JVM(Java虚拟机)

Java的主要特点是“编写一次,随处运行”。该特性说明我们可以编写一次代码,然后在任何操作系统上或任何平台上使用它。我们的Java程序只能在任何平台上运行,因为Java虚拟机。它是Java平台组件,为我们提供了执行Java程序的环境。JVM的主要任务是将字节码转换为机器码。

现在让我们逐个查看每个组件。

ClassLoader子系统

ClassLoader子系统负责以下三个活动。

1) 加载

2) 链接

2.1) 验证

2.2) 准备

2.3) 解析

3) 初始化

1. 加载

加载意味着读取类文件并在方法区中存储相应的二进制数据。

对于每个类文件,JVM在方法区中存储以下方法。

  • 加载的类或接口或枚举的完全限定名称。
  • 其直接父类的完全限定名称。
  • 变量信息
  • 方法信息
  • 修饰符信息
  • 常量池信息

在将.class文件加载到方法区后,JVM将立即创建一个Class类型的对象,以表示堆内存中的类级二进制信息。

例如:

类对象可由程序员用于获取类级信息,如类的完全限定名称、父名称、方法和变量信息等。

注意: 对于每个加载的.class文件,仅创建一个Class对象,即使我们在应用程序中多次使用类。

2. 链接

链接由3个活动组成

  • 验证
  • 准备
  • 解析

验证

这是确保类的二进制表示结构正确与否的过程。

也就是说,JVM将检查由有效编译器生成的.class文件是否正确格式化。

内部的字节码验证器是ClassLoader子系统的一部分,负责此活动。

如果验证失败,我们将获得运行时异常,表示java.lang.VerifyError。

准备

在这个阶段,JVM将为类级静态变量分配内存,并分配默认值(不是原始值)。注意: 原始值被分配到初始化部分。

解析

这是用加载的类型所使用的符号引用替换成原始引用的过程。

通过搜索方法区来定位引用实体,符号引用被解析为直接引用。

例如;

理解解析的程序

在上面的程序中,有三个类

  • 字符串类
  • 学生类
  • 对象类(对象类是所有Java类的父类)

对于上述程序,ClassLoader子系统加载Student.class、String.class和Object.class。

这些类名的名称存储在学生类的常量池中。

在解析阶段,这些名称将从方法区替换为实际引用。

3.初始化

在这个阶段,所有静态变量将被分配原始值,并且静态块将从顶部到底部以及从父类到子类执行。

因此ClassLoader子系统的总结如下图所示。

ClassLoader-SubSystem的总结

ClassLoader的类型

ClassLoader子系统包含以下三个ClassLoader。

  • 引导类加载器或原始类加载器
  • 扩展类加载器
  • 应用程序类加载器

引导类加载器

这个ClassLoader负责从** jdk\jre\lib**中加载类。

所有核心Java API类都存在于rt.jar中。这个位置上也有。因此,所有API类,如(String,StringBuffer)都只会由BootStrap ClassLoader加载。

它用原生语言CC++ 实现。

扩展类加载器

它是引导类加载器的子类。

这个ClassLoader负责从jdk\jre\lib\ext中加载类。

应用程序类加载器

它是扩展类加载器的子类。

这个ClassLoader负责从应用程序类路径(当前工作目录)中加载类。

它内部使用环境变量类路径。

让我们看看所有ClassLoader的例子

例如,

这里getClassLoader给出ClassLoader的路径

让我们看看上面程序的输出是什么

上面Java程序的输出

对于String类,来自Bootstrap Class-Path的Bootstrap ClassLoader的输出是null,因为我们可以看到上面的BootStrap classpath是用C和**C++**实现的,所以Bootstrap ClassLoader不是Java对象。因此,在第一种情况下我们得到了null。

Ketan类是应用程序类加载器的一部分,因为我们可以在当前工作目录中获取Ketan.class文件。

JVM的各种内存区域

在加载和运行Java程序时,JVM需要存储多种内容,如字节码、对象、变量等。

总JVM内存分为以下5类:

  • 方法区
  • 堆区或堆内存
  • Java堆栈区
  • PC寄存器区
  • 本地方法堆栈区

方法区

方法区将在JVM启动时创建。

它将由所有线程共享(全局内存)。

这个内存区域不需要连续。

方法区显示运行时常量池。

在方法区中存储总类级二进制信息,包括静态变量。

方法区

堆区

从程序员的角度来看,堆区被认为是一个重要的内存区域。

堆区可以被所有线程(全局或共享内存)访问。

堆区不需要连续。

所有对象和相应的实例变量将存储在堆区中。

Java中的每个数组都是一个对象,因此数组也将仅存储在堆内存中。

堆内存

堆栈内存

对于每个线程,JVM将创建一个单独的运行时堆栈。

运行时堆栈将在线程创建时自动创建。

所有方法调用和相应的本地变量、中间结果都将存储在堆栈中。

对于每个方法调用,将向堆栈添加一个单独的条目,该条目称为堆栈帧。在完成该方法调用后,将从堆栈中删除相应的条目。

存储在堆栈中的数据只能由相应的线程访问,对于其他线程是不可用的

堆栈区

PC Register Area(程序计数器)

对于每个线程,将在线程创建时创建一个单独的PC寄存器。

PC寄存器包含当前执行指令的地址。

一旦指令执行完成,PC寄存器将自动递增以保存下一条指令的地址。

本地方法堆栈

对于每个线程,JVM将创建一个单独的本地方法堆栈。

线程调用的所有本地方法调用将存储在相应的本地方法堆栈中。

注意:

方法区和堆区是针对JVM的。而堆栈区、PC寄存器区和本地方法堆栈区是针对线程的。

JVM 内存模型

在 JVM 中,每个 JVM 实例都有自己的堆内存、方法区和本地方法栈,每个线程都有自己的栈和 PC 寄存器。

堆内存

静态变量存储在方法区,实例变量存储在堆内存,局部变量存储在栈中。

执行引擎

执行引擎是 JVM 的核心组件,负责执行 Java 类文件。执行引擎包含两个组件来执行 Java 类。

  • 解释器
  • JIT 编译器

解释器

解释器负责读取字节码并将其解释(转换)为机器码(本机代码),然后逐行执行该机器码。

解释器的问题是即使同一方法被多次调用,它也会被解释多次。这会降低系统的性能。

为了解决这个问题,SUN 在 1.1 版本中引入了 JIT 编译器。

JIT 编译器

JIT 编译器的主要目的是提高性能,这是 Java 解释器的一个缺点。

JIT 编译器内部维护每个方法的计数器。每当 JVM 遇到任何方法调用时,该方法将被解释器正常解释,并且 JIT 编译器会递增相应的计数变量。

这个过程对于每个方法都会继续进行。

一旦任何方法计数达到阈值(新状态的起始点),JIT 编译器就会识别出该方法是重复使用的方法。

立即 JIT 编译器编译该方法并生成相应的本机代码。下一次 JVM 遇到该方法调用时,JVM 直接使用本机代码并执行它,而不是再次解释它。因此,系统的性能将得到改善。

阈值计数值因 JVM 而异。一些高级 JIT 编译器会在计数第二次达到阈值时重新编译生成的本机代码,以便生成更优化的机器代码。

执行引擎总结

JVM 至少一次逐行解释整个程序。

JIT 编译仅适用于重复调用的方法。但不适用于每个方法。

译自:https://medium.com/@ghoriketan33/java-architecture-92471787268b

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
阿波
The minute I see you, I want your clothes gone!

评论(0)

添加评论