JVM---JavaVirtualMachine(Java虚拟机)

2 篇文章 0 订阅

一、什么是JVM

虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器堆栈寄存器等,还具有相应的指令系统。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

二、JVM的基本介绍

2.1 JVM跨平台原理

  • 跨平台:由Java编写的程序可以在不同的操作系统上运行:一次编写,多处运行。
  • 原理:编译之后的字节码文件和平台无关,需要在不同的操作系统上安装一个对应版本的虚拟机(JVM) 

2.2 JVM的组成

2.3 Java文件是如何被运行的

JVM 是不认识文本文件的,所以它需要一个 编译 ,让其成为一个它会读二进制文件的 HelloWorld.class。

① 类加载器

如果 JVM 想要执行这个 .class 文件,我们需要将其装进一个 类加载器 中,它就像一个搬运工一样,会把所有的 .class 文件全部搬进JVM里面来。

② 方法区

方法区 是用于存放类似于元数据信息方面的数据的,比如类信息,常量,静态变量,编译后代码···等 ,类加载器将 .class 文件搬过来就是先丢到这一块上。

③ 堆

主要放了一些存储的数据,比如对象实例,数组···等,它和方法区都同属于 线程共享区域 。也就是说它们都是 线程不安全

④ 栈

这是我们的代码运行空间。我们编写的每一个方法都会放到 里面运行。

我们会听说过 本地方法栈 或者 本地方法接口 这两个名词,不过我们基本不会涉及这两块的内容,它俩底层是使用C来进行工作的,和Java没有太大的关系。

⑤ 程序计数器

主要就是完成一个加载工作,类似于一个指针一样的,指向下一行我们需要执行的代码。和栈一样,都是 线程独享 的,就是说每一个线程都会有自己对应的一块区域而不会存在并发和多线程的问题。

三、类加载器的介绍

之前也提到了它是负责加载.class文件的,它们在文件开头会有特定的文件标示,将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构,并且ClassLoader只负责class文件的加载,而是否能够运行则由 Execution Engine 来决定

3.1 类的加载流程(生命周期)

从类被加载到虚拟机内存中开始,到释放内存总共有7个步骤:加载,验证,准备,解析,初始化,使用,卸载。其中验证,准备,解析三个部分统称为连接

3.1.1 加载

  1. 将class文件加载到内存

  2. 将静态数据结构转化成方法区中运行时的数据结构

  3. 在堆中生成一个代表这个类的 java.lang.Class对象作为数据访问的入口

3.1.2 连接

  1. 验证:确保加载的类符合 JVM 规范和安全,保证被校验类的方法在运行时不会做出危害虚拟机的事件,其实就是一个安全检查

  2. 准备:为static变量在方法区中分配内存空间,设置变量的初始值,例如 static int a = 3 (注意:准备阶段只设置类中的静态变量(方法区中),不包括实例变量(堆内存中),实例变量是对象初始化时赋值的)

  3. 解析:虚拟机将常量池内的符号引用替换为直接引用的过程(符号引用比如我现在import java.util.ArrayList这就算符号引用,直接引用就是指针或者对象地址,注意引用对象一定是在内存进行)

3.1.3 初始化

初始化其实就是一个赋值的操作,它会执行一个类构造器的()方法。由编译器自动收集类中所有变量的赋值动作,此时准备阶段时的那个 static int a = 3 的例子,在这个时候就正式赋值为3

3.1.4 卸载

GC将无用对象从内存中卸载

3.2 类加载器的加载顺序

java程序并不是一个可执行文件,是由多个独立的类文件组成。这些类文件并不是一次性全部装入内存,而是依据程序逐步载入。JVM的类加载是通过ClassLoader及其子类来完成的,类的层次关系和加载顺序可以由下图来描述:

1)Bootstrap ClassLoader   启动类加载器

 是JVM的根ClassLoader,由C++实现;加载Java的核心API:$JAVA_HOME中jre/lib/rt.jar中所有class文件的加载,这个jar中包含了java规范定义的所有接口以及实现;JVM启动的时候就开始初始化此ClassLoader。

2)Extension ClassLoader     扩展类加载器

加载java扩展API(lib/ext中的类)

3)App ClassLoader    应用类加载器

加载Classpath目录下定义的class

 4)Custom ClassLoader    自定义类加载器

属于应用程序根据自身需要自定义的ClassLoader,如tomcat、Jboss都是会根据J2EE规范自行实现ClassLoader 

注意:加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。

3.3 双亲委派机制

定义:当一个类收到了加载请求时,它是不会先自己去尝试加载的,而是委派给父类去完成。

举例:

public class StringTest {
    public static void main(String[] args) {
        String string = new String();
        System.out.println("你好,Java");
    }
}

输出结果:你好,Java

我们都知道,String是java.lang包下面的类,那如果我自己创建一个java.lang包,然后在这个包下面建一个String对象,那么他会去加载哪个String呢?我们下面来看一下。新建java.lang包,写一个String类:

package java.lang;
public class String {
    static {
        System.out.println("自定义String类的静态代码块");
    }
}

我们继续运行,发现还是输出的:你好,Java

根据输出结果,我们可以知道,它并没有去加载我们自定义的String类,而是加载的Java自带的那个String类,这是为什么呢?我们接下来讨论。

工作原理:

 1、如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,
2、如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器。
3、如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。

双亲委派机制优势:

1、避免类的重复加载
2、保护程序安全,防止核心API被随意篡改,从一定程度上防止了危险代码的植入。
​ ->自定义类:java.lang.String
​ ->自定义类:java.lang.ShkStart

沙箱安全机制:

Java程序对类的使用方式分为:主动使用和被动使用

  • 主动使用,又分为7中情况:
    • 创建类的实例
    • 访问某个类或接口的静态变量,或者对该静态变量赋值
    • 调用类的静态方法
    • 反射(比如:Class.forName("com.shiro.test"))
    • 初始化一个类的子类
    • Java虚拟机启动时被标明为启动类的列
    • JDK 7 开始提供的动态语言支持:
      • Java.lang.invoke.MethodHandle实例的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic句柄对应的类没有初始化,则初始化
  • 除了以上七种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化

其他

在JVM中表示两个class对象是否为同一个类存在的两个必要条件:
	1、类的完整类名必须一致,包括包名
	2、加载这个类的ClassLoader(指ClassLoader实例对象)必须相同

换句话说,在JVM中,即使这两个类对象(Class对象)来源同一个Class文件,被同一个虚拟机所加载,但只要加载他们的ClassLoader实例对象不同,那么这两个类对象也是不相等的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值