这篇文章我们关注一个问题:Java程序是怎么进入JVM并执行的?经常写Java程序的小伙伴应该都听说过类加载机制,在《深入理解Java虚拟机》里周老师已经讲的很清楚了,这篇随笔把之前的笔记以及一些总结重新梳理一下。前面我们已经知道 .java文件经过编译后变成Class文件,JVM加载的是字节码文件。这其中的细节不知道小伙伴们有么有了解过?

   类从被JVM加载到内存开始,到卸载出内存为止,整个生命周期包括7个阶段,加载、验证、准备、初始化、卸载这个5个步骤顺序是确定的。

  • 加载,类的加载时机由JVM自行决定,JVM需要完成3件事情:

    • 通过类的全限定名获取类的二进制字节流
    • 将类的静态存储结构转化为方法区的运行时数据结构
    • 在内存中生成类的Class对象,作为方法区数据的入口

  数组在Java中是一种引用类型,数组类的加载由Java虚拟机直接创建。类加载完成后,二进制字节流存储在方法区中,HotSpot虚拟机会创建一个java.lang.Class对象作为程序访问方法区中的数据的外部接口,这个Class对象存储在方法区中,加载阶段何连接部分阶段是交叉进行的。

  • 验证是连接部分的第一步,验证阶段是确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。因为只有在字节码层面才能保证Java语言的相对安全性。验证阶段会大致完成4个阶段的检验动作:

    • 文件格式验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的JVM处理。只有验证通过了,字节流才会进入方法区存储。
    • 元数据验证:比如类是否有父类,类是否继承了不能被继承的类等,保证不存在不符合Java语言规范的元数据信息。
    • 字节码验证:对类的方法体进行校验分析
    • 符号引用验证:对常量池中的各种符号引用进行校验
  • 准备:为类变量分匹内存并设置类型变量的零值阶段。类变量指的是被static修饰的变量,不包括实例变量。例如变量i,在准备阶段值就是0L,只有在执行方法的时候值才会变成1。
private static long a = 1;
  • 解析:JVM将常量池内的符号引用替换为直接引用的过程。这里要解释下符号引用何直接引用。

    • 符号引用: 用一组符号描述所引用的目标,引用的目标不一定已经加载到内存中。
    • 直接引用:直接指向目标的指针、相对偏移量、间接定位到目标的句柄,直接引用的目标已经在内存中。
  • 初始化,类加载过程的最后一步,执行类构造器<clinit>()方也就是真正执行类中定义的Java程序代码。遇到使用new关键字实例化对象、读取或设置一个类的静态字段、调用一个类的静态方法这些场景时,如果类没有被初始化,使用java.lang.reflect包的方法对类进行 反射调用时,那么一定要先初始化。还有一种场景是初始化子类时,如果父类没有被初始化,那么要先初始化父类。再看下接口的初始化,与类不同的地方就在于父类的初始化,子接口在使用到父接口的时候才初始化。在多线程环境中,如果多个线程同时初始化一个类,那么只有线程执行类的<clinit>()方法。

  JVM加载字节码文件靠的是类加载器,这个操作是在JVM外部实现的。这样应用程序就可以自己决定如何获取所需的类。如果两个类来自同一个Class文件,但是由不同的类加载器加载,那么者两个类一定是不相等。从JVM角度讲,只有两种加载器。一种是启动类加载器,是虚拟机自身的一部分,由C++语言实现;还有就是其他类加载器,由Java语言实现,全都继承自抽象类java.lang.ClassLoader 独立于虚拟机外部。

  从开发角度看,主要分为这三种:

  • 启动类加载器(Bootstrap ClassLoader):加载<JAVA_HOME>\lib目录中,或者被 -Xbootclasspath参数所指定的路径中。
  • 扩展类加载器(Extension ClassLoader):主要加载<JAVA_HOME>\lib\ext目录中的
  • 应用程序类加载器(Application ClassLoader):加载用户类路径(ClassPath)上所指定的类库。如果我们没有自定义过自己的类加载器,那么这就是程序默认的类加载器。

  这些类加载器之间的关系为:

  在使用类加载器加载类的过程种,最好遵循双亲委派模型。双亲委派的原理是:类加载器收到加载类的请求时,先把这个请求委派给父类加载去完成,每一层次的加载器按这个这个逻辑执行。那么所有的加载请求最终都应该传送到顶层的启动类加载中。父加载器无法加载,子加载器才会自己加载。这样做的好处是可以避免类的重复加载,保证程序运行的稳定性。

  我们可以自定义类加载器,总结起来就是:(1)类继承ClassLoader (2) 重写findClass() 方法 (3) 调用defineClass()方法。在loadClass()里如果父类加载失败,调用findClass()方法加载。破会双亲委派需要重写loadClass()方法。

  参考资料:《深入理解Java虚拟机》第二版 周志明

       《深入拆解Java虚拟机》郑雨迪

JVM类加载机制小结的更多相关文章

  1. JVM基础系列第7讲:JVM 类加载机制

    当 Java 虚拟机将 Java 源码编译为字节码之后,虚拟机便可以将字节码读取进内存,从而进行解析.运行等整个过程,这个过程我们叫:Java 虚拟机的类加载机制.JVM 虚拟机执行 class 字节 ...

  2. JVM总结(四):JVM类加载机制

    这一节我们来总结一下JVM类加载机制.具体目录如下: 类加载的过程 类加载过程概括 说说引用 详解类加载全过程: 加载 验证 准备 解析 初始化 虚拟机把描述类的数据从Class文件加载到内存,并对数 ...

  3. JVM 类加载机制详解

    如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lan ...

  4. Java虚拟机(四):JVM类加载机制

    1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...

  5. JVM类加载机制详解(二)类加载器与双亲委派模型

    在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...

  6. JVM类加载机制(转)

    原文出自:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运 ...

  7. JVM类加载机制详解

    引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...

  8. Android动态加载--JVM 类加载机制

    动态加载,本质上是通过JVM类加载机制将插件模块加载到宿主apk中,并通过android的相关运行机制,实现插件apk的运行.因此熟悉JVM类加载的机制非常重要. 类加载机制:虚拟机把描述类的数据从C ...

  9. Java虚拟机(五):JVM 类加载机制

    一.JVM 类加载机制 JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 1. 加载: 加载是类加载过程中的第一个阶段,这个阶段会在内存中生成一个代表 ...

随机推荐

  1. Linux 日志轮替

    日志轮替包括两个方面的内容:切割日志文件,轮换日志文件 日志文件的命令规则 如果配置文件中有dateext参数,那么日志文件的后缀会是日期,例如:yum.log-20200424,这样,文件名不会重叠 ...

  2. 用js实现简单的抛物线运动

    前言 老早就看过一些购物车的抛物线效果,也想自己凑热闹动手来实现一遍. 然后(lll¬ω¬) 书到用时方恨少,发现高中学到物理啊.数学啊,都忘光了,抛物线公式都忘了0 0. 顺手百度一波,从百度可知: ...

  3. 【Mysql】使用一条sql查询出库表结构信息

    1.新建查询 将以下脚本粘贴进去 脚本如下: SELECT TABLE_SCHEMA 库名, TABLE_NAME 表名, COLUMN_NAME 列名, COLUMN_TYPE 数据类型, DATA ...

  4. BFART算法

    参考:https://zhuanlan.zhihu.com/p/31498036 https://www.jianshu.com/p/83bb10ad1d32

  5. Volley框架学习资料汇总

    Android Volley完全解析(一),初识Volley的基本用法(http://blog.csdn.net/guolin_blog/article/details/17482095/)

  6. RocketMQ系列(四)顺序消费

    折腾了好长时间才写这篇文章,顺序消费,看上去挺好理解的,就是消费的时候按照队列中的顺序一个一个消费:而并发消费,则是消费者同时从队列中取消息,同时消费,没有先后顺序.RocketMQ也有这两种方式的实 ...

  7. js原型链、继承、this指向等老生常谈却依然不熟的知识点——记录解析

    开始记录学习过程—— 很详细的解析过程——https://juejin.im/post/5c72a1766fb9a049ea3993e6 借鉴阅读——https://github.com/KieSun ...

  8. ROS 机器人技术 - 解决 ROS_INFO 不能正确输出 string 的问题!

    一.输出「??」 项目调试一个节点,打印 ROS 信息时发现设置的节点名称都是问号: ROS_INFO("[%s]: camera_extrinsic_mat", kNodeNam ...

  9. hadoop知识整理(5)之kafka

    一.简介 来自官网介绍: 翻译:kafka,是一个分布式的流处理平台.LinkedIn公司开发.scala语言编写.   1.支持流处理的发布订阅模式,类似一个消息队列系统: 2.多备份存储,副本冗余 ...

  10. @codeforces - 594E@ Cutting the Line

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个字符串 s 与正整数 k.现在你需要进行恰好一次操作: ...