JVM(Java虚拟机)充当运行Java应用程序的运行时引擎。 JVM是实际上称为主要Java代码中存在的方法。 JVM是JRE(Java运行时环境)的一部分。
Java应用程序称为WORA(可在任何地方写入一次)。这意味着程序员可以在一个系统上开发Java代码, 并且可以期望它在任何其他启用Java的系统上运行, 而无需进行任何调整。由于JVM, 所有这些都是可能的。
当我们编译一个.java文件, 。类具有相同类名的文件(包含字节码).java文件由Java编译器生成。这个。类文件在运行时会进入各个步骤。这些步骤共同描述了整个JVM。
类加载器子系统
它主要负责三项活动。
- 载入中
- 连结中
- 初始化
正在加载:类加载器读取。类文件, 生成相应的二进制数据并将其保存在方法区域中。对于每个。类文件, JVM将以下信息存储在方法区域中。
- 加载的类及其直接父类的全限定名称。
- 是否。类文件与类或接口或枚举有关
- 修饰符, 变量和方法信息等
加载后。类在文件中, JVM创建类型为Class的对象来表示该文件在堆内存中。请注意, 此对象的类型为在java.lang包。程序员可以使用此Class对象来获取类级别的信息, 例如类名称, 父名称, 方法和变量信息等。要获取此对象引用, 我们可以使用getClass()的方法Object类。
// A Java program to demonstrate working of a Class type
// object created by JVM to represent .class file in
// memory.
import java.lang.reflect.Field;
import java.lang.reflect.Method;
// Java code to demonstrate use of Class object
// created by JVM
public class Test
{
public static void main(String[] args)
{
Student s1 = new Student();
// Getting hold of Class object created
// by JVM.
Class c1 = s1.getClass();
// Printing type of object using c1.
System.out.println(c1.getName());
// getting all methods in an array
Method m[] = c1.getDeclaredMethods();
for (Method method : m)
System.out.println(method.getName());
// getting all fields in an array
Field f[] = c1.getDeclaredFields();
for (Field field : f)
System.out.println(field.getName());
}
}
// A sample class whose information is fetched above using
// its Class object.
class Student
{
private String name;
private int roll_No;
public String getName() { return name; }
public void setName(String name) { this .name = name; }
public int getRoll_no() { return roll_No; }
public void setRoll_no( int roll_no) {
this .roll_No = roll_no;
}
}
输出如下:
Student
getName
setName
getRoll_no
setRoll_no
name
roll_No
注意 :每次加载。类仅文件一创建了Class对象。
Student s2 = new Student();
// c2 will point to same object where
// c1 is pointing
Class c2 = s2.getClass();
System.out.println(c1==c2); // true
连结:执行验证, 准备和(可选)解决方案。
- 验证:它确保了正确性。类文件, 即它检查此文件是否由有效的编译器正确格式化和生成。如果验证失败, 我们将获得运行时异常java.lang.VerifyError.
- 制备:JVM为类变量分配内存, 并将内存初始化为默认值。
- 解析度:这是用直接引用替换类型中的符号引用的过程。通过搜索方法区域以找到引用的实体来完成此操作。
初始化:
在此阶段, 将为所有静态变量分配在代码和静态块(如果有)中定义的值。在类中从上到下执行, 在类层次结构中从上到下执行。
通常, 有三种装载机:
- 引导类加载器注意:每个JVM实现都必须具有一个引导类加载器, 该加载器能够加载受信任的类。加载存在于Java的核心Java API类JAVA_HOME / jre / lib目录。该路径通常称为引导路径。它以C, C ++等本地语言实现。
- 扩展类加载器:是引导程序类加载器的子级。它加载扩展目录中存在的类JAVA_HOME / jre / lib / ext(扩展路径)或java.ext.dirs系统属性指定的任何其他目录。它是由Java实现的sun.misc.Launcher $ ExtClassLoader类。
- 系统/应用程序类加载器:是扩展类加载器的子级。它负责从应用程序类路径加载类。它在内部使用映射到java.class.path的环境变量。它也由Java用Java实现。sun.misc.Launcher $ AppClassLoader类。
// Java code to demonstrate Class Loader subsystem
public class Test
{
public static void main(String[] args)
{
// String class is loaded by bootstrap loader, and
// bootstrap loader is not Java object, hence null
System.out.println(String. class .getClassLoader());
// Test class is loaded by Application loader
System.out.println(Test. class .getClassLoader());
}
}
输出如下:
null
sun.misc.Launcher$AppClassLoader@73d16e93
注意 :JVM遵循委派层次结构原则来加载类。系统类加载器将加载请求委托给扩展类加载器, 扩展类加载器将请求委托给引导类加载器。如果在引导路径中找到了类, 则将装入该类, 否则再次将请求传输到扩展类加载器, 然后再传输到系统类加载器。最后, 如果系统类加载器无法加载类, 则会得到运行时异常java.lang.ClassNotFoundException.
JVM内存
方法范围:
在方法区域中, 将存储所有类级别信息, 例如类名称, 直接父类名称, 方法和变量信息等, 包括静态变量。每个JVM只有一个方法区域, 它是共享资源。
堆面积:所有对象的信息都存储在堆区域中。每个JVM还有一个堆区。它也是共享资源。
堆放面积:JVM为每个线程创建一个运行时堆栈, 该堆栈存储在此处。该堆栈的每个块称为存储方法调用的激活记录/堆栈帧。该方法的所有局部变量都存储在其相应的框架中。线程终止后, 其运行时堆栈将被JVM破坏。它不是共享资源。
PC寄存器:存储线程当前执行指令的地址。显然, 每个线程都有单独的PC寄存器。
本机方法栈:对于每个线程, 将创建单独的本机堆栈。它存储本机方法信息。
执行引擎
执行引擎执行
。类
(字节码)。它逐行读取字节码, 使用存在于各个存储区中的数据和信息并执行指令。它可以分为三个部分:
- 口译员:逐行解释字节码, 然后执行。此处的缺点是, 当多次调用一种方法时, 每次都需要解释。
- 即时编译器(JIT):用于提高解释器的效率。它编译整个字节码并将其更改为本地代码, 因此每当解释器看到重复的方法调用时, JIT都会为该部分提供直接的本地代码, 因此不需要重新解释, 从而提高了效率。
- 垃圾收集器:销毁未引用的对象。有关垃圾收集器的更多信息, 请参阅垃圾收集器.
Java本机接口(JNI):
它是一个与本机方法库交互的接口, 并提供执行所需的本机库(C, C ++)。它使JVM可以调用C / C ++库, 并可以由特定于硬件的C / C ++库调用。
本机方法库:
它是执行引擎所需的本机库(C, C ++)的集合。
如果发现任何不正确的地方, 或者想分享有关上述主题的更多信息, 请写评论。