类加载机制

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

类加载的时机

  • 遇到new(比如new Student())、getstatic和putstatic(读取或设置一个类的静态字段,如下代码,读取被final修饰并已在编译器把结果放入常量池的静态字段除外)、invokestatic(调用类的静态方法)这四条指令时,如果对应的类没有初始化,则要对对应的类先进行初始化。
public class Student{
private static int age;
public static void method(){
}
}
Student.age
Student.method();
  • 使用java.lang.reflect包方法时对类进行反射调用的时候。
  • 初始化一个类的时候发现其父类还没初始化,要先初始化其父类。
  • 当虚拟机开始启动时,用户需要指定一个主类(main),虚拟机会限制性这个主类的初始化。

类加载的过程

类加载过程是如下图所示的一个流水线过程,其中连接过程可细化为验证、准备和解析三个小步骤。

加载

class文件–>class对象

“加载”过程主要是靠类加载器实现的,包括用户自定义类加载器。

加载的过程

在加载过程中,JVM主要做以下3件事:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流(class文件)。在程序运行过程中,当要访问一个类时,若发现这个类尚未被加载,并满足类初始化的条件时,就根据要被初始化的这个类的全限定名找到该类的二进制字节流,开始加载过程
  2. 将这个字节流的静态存储结构转化为方法区的运行时数据结构(即Class对象)
  3. 在内存中创建一个该类的java.lang.Class对象,作为方法区该类的各种数据的访问入口

程序在运行中所有对该类的访问都通过这个类对象,也就是这个Class对象是提供给外界访问该类的接口。

加载源

JVM规范对于加载过程给予了较大的宽松度,一般二进制字节流都从已经编译好的本地class文件中读取,此外还可以从这些地方读取:zip包(jar、war、ear等),由jsp文件中生成对应的Class类,数据库,网络,运行时计算生成(动态代理技术)。

加载过程的注意点

  • 类和数组加载的区别:非数组类是由类加载器来完成;数组类本身不通过类加载器创建,它是由java虚拟机直接创建,但数组类与类加载器有很密切的关系,因为数组类的元素类型最终要靠类加载器创建。
  • HotSpot将Class对象存放在方法区

验证

各种检查

验证阶段比较耗时,它非常重要但不一定必要,可用-Xverify:none参数关闭,以缩短类加载时间。

验证的目的

保证二进制字节流的信息符合虚拟机规范,并没有安全问题。

验证的必要性

Java语言的安全性是通过编译器来保证的,但编译器和虚拟机是两个独立的东西,虚拟机只认二进制字节流,它不会管所获得的二进制字节流是哪来的。当然,如果是编译器给它的那么就相对安全,但如果是从其它途径获得的,那么无法确保该二进制字节流是安全的。

验证的过程

其中文件格式验证阶段是基于二进制字节流进行的,只有通过本阶段验证,才被允许存放到方法区。后面的三个验证阶段都是基于方法区的存储结构进行,不会再直接操作字节流。

准备

为static分配内存并初始化0值。JDK1.7之前在方法区,1.7之后在堆。

仅仅为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即零值,这里不包含用final修饰的static,因为final在编译的时候就会分配好,同时这里也不会为实例变量分配初始化。类变量(静态变量)会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。

准备阶段主要完成两件事情:

  • 为已在方法区中的类的静态成员变量分配内存;
  • 为静态成员变量设置初始值,具体初始值为下图所示。

注意:

public static int x = 1000;

实际上变量x在准备阶段过后的初始值为0,而不是1000。将x赋值为1000是在初始化阶段完成。

解析

将符号引用替换为直接引用

解析是虚拟机将常量池的符号引用替换为直接引用的过程。

初始化

调用方法

初始化过程就是调用类初始化方法的过程,完成对static修饰的类变量的手动赋值还有主动调用静态代码块。

注意点:此步骤中虚拟机会保证在多线程环境中一个类的方法被正确地加锁(静态内部类)

类加载器介绍

启动类加载器:

由C++实现,不是ClassLoader子类。

负责加载JAVA_HOME\lib目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt,jar)的类。

扩展类加载器:

负责加载JAVA_HOME\lib\ext目录中的,或通过java.ext.dirs系统变量指定路径中的类库。

应用程序类加载器:

负责加载用户路径(classpath)上的类库。

自定义类加载器:

上述的加载器只能加载指定目录下的jar和class,如果想加载其他位置的jar或类时,则需要实现自定义类加载器来加载。

比如要加载网络上的一个class文件,通过动态加载到内存之后,要调用这个类中的方法实现特定业务逻辑,此时默认的ClassLoader就不能满足我们的需求,需要定义自己的ClassLoader。

双亲委派模型

JVM的类加载是通过多层次的类加载器来完成的,类的层次关系和加载顺序可以由下图来描述:

加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader组层检查,只要某个classloader已加载就视为已加载此类,保证此类只加载一次。而加载的顺序是自顶向下,也就是由上层来组层尝试加载此类。这种类加载的层次关系就是双亲委派模型。

需注意的点:

  • 当一个类加载器收到类加载任务,会先交给其父类加载器去完成,因此最终加载任务都会传递到顶层的启动类加载器;
  • 只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。

为什么使用双亲委派这种模型

因为这样可以避免类的重复加载,当父classloader经加载了该类的时候,就没必要子classloader再加载一次。

考虑到安全因素,我们试想一下,如果不适用这种委托模型,那我们就可以随时使用自定义的String来动态替代java核心api重定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况。因为String已经在启动时就被Bootstrap ClassLoader加载,所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非改编JDK中ClassLoader搜索类的默认算法。

判定两个Class对象是否相同的依据

  • class字节码是否相同
  • ClassLoader是否相同

JVM在判定两个class是否相同,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。类的全限定名完全相同,但是加载它的类加载器不同,那么在方法区中会产生不同的Class对象。

只有两者同时满⾜的情况下,JVM才认为这两个class是相同的。就算两个class是同⼀份class字节码,如果被两个不同的ClassLoader实例所加载,JVM也会认为它们是两个不同class。

破坏双亲委派模型

为什么需要破坏双亲委派

因为在某些情况下父类加载器需要加载的class文件由于受到加载范围的限制,父类加载器无法加载到需要的文件,这个时候就需要委托子类加载器进行加载。

双亲委派模型是在JDK1.2以后才使用的,但是有一些核心的API类在JDK1.2之前就已经写好了。

简单理解双亲委派模型是子类加载器去委托父类加载器完成类加载的工作,而破坏双亲委派模型是父类加载器去委托子类加载器完成类加载的工作。

以Driver接口为例,由于Driver接口定义在jdk当中,而其实现由各个数据库的服务商来提供,比如mysql就写了MySQL Connector,这些实现类都是以jar包的形式放到classpath目录下。

那么问题就来了,DriverManager(也由jdk提供,JDK1.2之前就写好了)要加载各个实现了Driver接口的实现类(在classpath下),然后进行管理,但是DriverManager由启动类加载器加载,只能加载JAVA_HOME\lib下的文件,而其实现是由服务商提供的,有系统类加载器加载,这个时候就需要启动类加载器来委托子类加载器来加载Driver实现,从而破坏了双亲委派。如下图所示。

最后

欢迎关注公众号:前程有光,领取一线大厂Java面试题总结+各知识点学习思维导+一份300页pdf文档的Java核心知识点总结!

JVM类加载机制详解,建议看这一篇就够了,深入浅出总结的十分详细!的更多相关文章

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

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

  2. JVM类加载机制详解

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

  3. JVM 类加载机制详解

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

  4. 面试题:JVM类加载机制详解(一)JVM类加载过程 背1

    首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1.什么是类加载?什么时候进行类加载? 2.什么是类初始化?什么时候进行类初始化? 3.什么时候会为变量分配内存? 4.什么时候会为变量赋默 ...

  5. JVM类加载机制详解(一)JVM类加载过程

    http://blog.csdn.net/zhangliangzi/article/details/51319033 http://chenzhou123520.iteye.com/blog/1597 ...

  6. Linux 虚拟网络设备 veth-pair 详解,看这一篇就够了

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 前面这篇文章介 ...

  7. 【K8S】Service服务详解,看这一篇就够了!!

    k8s用命名空间namespace把资源进行隔离,默认情况下,相同的命名空间里的服务可以相互通讯,反之进行隔离. 1.1 Service Kubernetes中一个应用服务会有一个或多个实例(Pod, ...

  8. Java程序员的必备知识-类加载机制详解

    类加载器的概念 类加载器是一个用来加载类文件的类. Java源代码通过javac编译器编译成类文件.然后JVM来执行类文件中的字节码来执行程序.类加载器负责加载文件系统.网络或其他来源的类文件. JV ...

  9. SPA路由机制详解(看不懂不要钱~~)

    前言 总所周知,随着前端应用的业务功能起来越复杂,用户对于使用体验的要求越来越高,单面(SPA)成为前端应用的主流形式.而大型单页应用最显著特点之一就是采用的前端路由跳转子页面系统,通过改变页面的UR ...

随机推荐

  1. CSS动画之过渡模块

    :hover伪类选择器可以用于所有的选择器(只有在悬停时,执行选择器的属性)CSS3中新增过渡模块:transition property(属性)duration(过渡效果花费的时间)timing-f ...

  2. Go语言反射(reflect)及应用

    Go语言反射(reflect)及应用 基本原理及应用场景 在编译时不知道类型的情况下,可更新变量.在运行时查看值.调用方法以及直接对它们的布局进行操作,这种机制被称为反射. 具体的应用场景大概如下: ...

  3. 正式班D21

    2020.11.03星期二 正式班D21 目录 11.5 源码包 11.5.1 预先安装编译安装依赖的库 11.5.2 官网下载源码包 11.5.3 解压.编译.编译安装 11.5 源码包 11.5. ...

  4. Nodejs在VSCode下代码智能提示

    在学习Nodejs的过程中发现vscode下默认没有提示,在网上也测试了传统的一些方法,都不好用,最后找到这个npm install --save-dev @types/node

  5. 编码风格:Mvc模式下SSM环境,代码分层管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.分层策略 MVC模式与代码分层策略,MVC全名是ModelViewController即模型-视图-控制器,作为一种软件设计典范,用一种业 ...

  6. 数据库会话数量过多,定期清理inactive会话

    1.1现象 存在一套11.2.0.4 RAC 2节点,数据库存在5000个会话数量,其中active正在执行的会话500个,其余均为非活跃会话. 大量inactive会话过多给Oracle数据库带来什 ...

  7. python数据分析01准备工作

    第1章 准备工作 1.1 本书的内容 本书讲的是利用Python进行数据控制.处理.整理.分析等方面的具体细节和基本要点.我的目标是介绍Python编程和用于数据处理的库和工具环境,掌握这些,可以让你 ...

  8. 利用Servlet做一套增删改查

    真的,稳住,考上研,利用两年逆袭.一步一步来,实在不行,最后最差也不过就是就回家种地,想想也不错. 前期准备配置 建一个动态web项目 新建Dynamic Web ProjectFile->Ne ...

  9. 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(2) - 识别当前i.MXRT型号

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(2)之识别当前i.MXRT型号. 文接上篇 <超级下载算法(RT-UFL)开发笔记(1) - 执行在不同CM ...

  10. 人体动作捕捉格式之BVH

    BVH简介 BVH是BioVision公司推出的一种人体动作捕捉文件格式.这种文件以节点为核心元素,记录连续数帧内人体骨架的运动. BVH=? 研究一个东西的时候我比较喜欢先研究它的名字.BVH可以认 ...