• JVM学习第一天


    JVM的架构模型

    Java编译器输入的指令流基本上是一种基于栈的指令集架构,另外一种指令集架构则是基于寄存器的指令集架构。
    具体来说,两种架构之间的区别是:
    基于栈式架构的特点:
    (1)设计和实现更加简单,适用于资源受限的系统。
    (2)避开了寄存器的分配难题:使用零地址指令方式(没有地址,只有操作数,也就是操作数地址个数为0)分配。
    (3)指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。指令集更小,编译器容易实现。
    (4)不需要硬件支持,可移植性更好,更好实现跨平台。
    基于寄存器架构的特点:
    (1)典型的应用是X86的二进制指令集:比如传统的PC以及Android的Davlik虚拟机。
    (2)指令集架构则完全依赖硬件,可移植性差。
    (3)性能优秀,执行效率更高。
    (4)花费更少的指令去完成一项工作。
    (5)在大部分情况下,基于寄存器架构的指令集往往都是一地址指令、二地址指令和三地址指令为主,而基于栈式架构的指令集却是以零地址指令为主。

    总结:
    栈,跨平台性、指令集小、指令多;执行性能比寄存器差。

    JVM的声明周期

    (1)虚拟机的启动
    Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。
    (2)虚拟机的执行
    一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序。
    程序开始执行时他才运行,程序结束时他就停止。
    执行一个所谓的Java程序的时候,真真正正在执行的是一个叫作Java虚拟机的进程。
    (3)虚拟机的退出
    程序正常结束
    程序在执行过程中遇到了异常或者错误而一擦和功能中止
    由于操作系统出现错误导致java虚拟机进程终止
    某线程调用Runtime类或者System类的exit方法,或者Runtime类的halt方法。

    类加载器子系统的作用

    在这里插入图片描述
    (1)类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。
    (2)ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine(执行引擎)决定。
    (3)加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池的信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)。

    类的加载过程

    加载:
    (1)通过一个类的全限定类名获取定义此类的二进制字节流
    (2)将这个字节流所代表的静态存储结构装华为方法区的运行时数据结构
    (3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问接口

    链接:
    (1)验证(Verify):
    目的在于确保Class文件中的字节流中包含信息符合当前虚拟机的要求,保证被加载类的正确性,不会危害虚拟机自身安全。
    主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
    (2)准备(Prepare)
    为类变量分配内存并且设置该类变量的默认初始值,即零值。
    这里不包含使用final修饰的static,因为final编译的时候就会分配了,准备阶段会显式初始化。
    这里不会为实例变量初始化,类变量分配在方法区的内存之中,而实例变量会随着对象一起分配到java堆之中。
    (3)解析(Resolve)
    将常量池内的符号引用转换为直接引用的过程。
    事实上,解析操作往往会伴随着JVM在执行完初始化之后再执行。
    符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义在《java虚拟机规范》的Class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
    解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的CONSTANT_CLASS_INFO、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。

    初始化:
    (1)初始化阶段就是执行类构造器方法()的过程。
    (2)此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。
    (3)构造器方法中指令按语句在源文件中出现的顺序执行。
    (4)()不同于类的构造器。(关联:构造器是虚拟机视角下的())
    (5)若该类具有父类,JVM会保证子类的()执行前,父类到的()已经执行完毕。
    (6)虚拟机必须保证一个类的()方法在多线程下被同步加锁

    在这里插入图片描述

    类加载器的分类

    (1)JVM支持两种类型的类加载器,分别是引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)。
    (2)从概念上讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象类ClassLiader的类加载器都划分为自定义类加载器。
    (3)无论类加载器的类型如何划分,再程序中我们最常见的类加载器始终只有3个,如下所示:
    在这里插入图片描述

    启动类加载器(也叫引导类加载器,Bootstrap ClassLoader)

    (1)这个类是由C/C++语言实现的,嵌套在JVM内部
    (2)它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar、resource.jar或者sun.boot.class.path路径下的内容),用于提供JVM自身需要的类
    (3)并不继承自java.lang.ClassLoader,没有父加载器
    (4)负责加载扩展类和应用程序类加载器,并指定为他们的父类加载器。
    (5)出于安全考虑,Bootstrap启动类加载器值加载包名为java、javax、sun等开头的类。

    扩展类加载器(Extension ClassLoader)

    (1)Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
    (2)派生于ClassLoader类
    (3)父类加载器为启动类加载器
    (4)从java.ext.dirs系统属性所制定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。

    获取ClassLoader的途径

    方式一:获取当前类的ClassLoader
    class.getClassLoader()
    方式二:获取当前线程上下文的ClassLoader
    Thread.currentThread().getContextClassLoader()
    方式三:获取系统的ClassLoader
    ClassLoader.getSystemClassLoader()
    方式四:获取调用者的ClassLoader
    DriverManager.getCallerClassLoader()

    双亲委派机制

    (1)如果一个类加载器收到类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。
    (2)如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器。
    (3)如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制。
    在这里插入图片描述
    优势:
    避免类的重复加载
    保护程序安全,防止核心API被篡改:
    自定义类:java.lang.String
    自定义类:java.lang.ShkStart

    沙箱安全机制

    自定义String类,但是在加载自定义String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件,(rt.jar包中java\lang\String.class),报错信息中说没有main 方法,就是因为加载的是rt.jar包中的String类。这样可以保护对java核心源代码的保护,这就是沙箱安全机制。

    在java中表示两个class对象是否为同一个类的必要条件

    (1)类的完整类名必须一致,包括包名
    (2)加载这个类的ClassLoader(指ClassLoader实例对象)必须相同
    换句话说,在jvm中,即使这两个类对象(class对象)来源同一个Class文件,被同一个虚拟机所加载,但只要加载它们的ClassLoader实例对象不同,那么这两个类对象也是不相等的。JVM必须知道一个类型是由启动类加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的引用作为类型信息的一部分保存在方法区中。当解析一个类型到另一个类型的引用的时候,JVM需要保证这两个类型的类加载器是相同的。

  • 相关阅读:
    浅述蓝牙Mesh的配网流程
    CIIS 2023丨聚焦文档图像处理前沿领域,合合信息AI助力图像处理与内容安全保障
    VBA之Word应用:文档(Document)的书签
    嵌入式Linux 学习笔记 (一) fbtft使用笔记
    矩阵的模和内积
    2022年11月23日——jQuery——T1(基础选择器与表单选择器)
    【SpringBoot学习】51、MybatisPlus 代码生成器、定制代码模板
    Thinkphp下载oss文件至本地压缩包
    idea全局搜索
    【开源教程17】疯壳·开源编队无人机-PID 基础原理
  • 原文地址:https://blog.csdn.net/weixin_49131718/article/details/127717616