42. JVM--类加载器详解

● 类加载器子系统作用:

1. 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。
2. ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。
3. 加载的类信息存放于一块称为方法区的内存空间。

● 类加载器ClassLoader作用:

1. class file,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载到JVM当中来根据这个文件实例化出n个一模一样的实例。
2. class file加载到JVM中,被称为DNA元数据模板,放在方法区。
3. 在.class文件–>JVM–>最终成为元数据模板,此过程就要一个运输工具(类装载器Class Loader),扮演一个快递员的角色。


● 类加载过程:

public class HelloLoader {public static void main(String[] args) {System.out.println("谢谢ClassLoader加载我....");System.out.println("你的大恩大德,我下辈子再报!");}
}

它的加载过程是怎么样的呢?
1、执行 main() 方法(静态方法)就需要先加载承载类 HelloLoader
2、加载成功,则进行链接、初始化等操作,完成后调用 HelloLoader 类中的静态方法 main
3、加载失败则抛出异常
完整的流程图如下所示: 加载 --> 链接(验证 --> 准备 --> 解析) --> 初始化
● 加载阶段:
加载流程:
1. 通过一个类的全限定名获取定义此类的二进制字节流
2. 将这个字节流所代表的静态存储结构转化为 方法区的运行时数据结构
3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
加载class文件的方式:
1. 从本地系统中直接加载
2. 通过网络获取,典型场景:Web Applet
3. 从zip压缩包中读取,成为日后jar、war格式的基础
4. 运行时计算生成,使用最多的是:动态代理技术
5. 由其他文件生成,典型场景:JSP应用从专有数据库中提取.class文件,比较少见
6. 从加密文件中获取,典型的防Class文件被反编译的保护措施
● 链接阶段:
链接分为三个子阶段:验证 --> 准备 --> 解析
● 验证(Verify):
1. 目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全
2. 主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
● 准备(Prepare):
1. 为类变量(static)分配内存并且设置该类变量的默认初始值
2. 这里不包含用final修饰的static,因为final在编译的时候就会分配好了默认值,准备阶段会显式初始化
3. 注意:这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中
案例:
代码:变量a在准备阶段会赋初始值,但不是1,而是0,在初始化阶段会被赋值为 1
public class HelloApp {private static int a = 1;public static void main(String[] args) {System.out.println(a);}
}

● 解析(Resolve):
1. 将常量池内的符号引用转换为直接引用的过程
2. 符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义在《java虚拟机规范》的class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄
3. 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的CONSTANT Class info、CONSTANT Fieldref info、CONSTANT Methodref info等
在编译的时候一个每个java类都会被编译成一个class文件,但在编译的时候虚拟机并不知道所引用类的地址,多以就用符号引用来代替,而在这个解析阶段就是为了把这个符号引用转化成为真正的地址的阶段。
String str = "abc";

初始化阶段:(重点)
1. 初始化阶段就是执行类构造器方法 <clinit>()</clinit> 的过程
2. 此方法不需定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。也就是说, 当我们代码中包含static变量的时候,就会有clinit方法
3. <clinit>()</clinit> 方法中的指令按语句在源文件中出现的顺序执行
4. <clinit>()</clinit>不同于类的构造器。(关联:构造器是虚拟机视角下的 <init>()</init>)
5. 若该类具有父类,JVM会保证子类的 <clinit>()</clinit> 执行前,父类的 <clinit>()</clinit> 已经执行完毕
6. 虚拟机必须保证一个类的 <clinit>()</clinit> 方法在多线程下被同步加锁
● 初始化案例:
当我们代码中包含static变量的时候,就会有clinit方法
1、无 static 变量:
2、有static变量:
3、构造器方法中指令按语句在源文件中出现的顺序执行
静态变量 number 的值变化过程如下
1、prepare准备阶段时:0
2、 执行静态变量初始化:10
3、 执行静态代码块:20
静态变量 number 的值变化过程如下
1、准备阶段时:0
2、执行静态代码块:20
3、执行静态变量初始化:10
4、若该类具有父类,JVM会保证子类的 <clinit>()</clinit> 执行前,父类的 <clinit>()</clinit> 已经执行完毕
加载流程如下:
1、首先,执行 main() 方法需要加载 ClinitTest1 类
2、 获取 Son.B 静态变量,需要加载 Son 类
3、Son 类的父类是 Father 类,所以需要先执行 Father 类的加载,再执行 Son 类的加载



● 类加载器的分类:

1. JVM支持两种类型的类加载器 。分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)。
2. 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范却没有这么定义,而是 将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器。
3. 无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有3个,如下所示。
4. 这里的四者之间是包含关系,不是上层和下层,也不是子父类的继承关系。
● 为什么 ExtClassLoader 和 AppClassLoader 都属于自定义加载器?
规范定义: 所有派生于ClassLoader的类加载器都划分为自定义类加载器,所以ExtClassLoader和AppClassLoader也归类到自定义类加载器。
BootstrapClassLoader是用C、C++语言写的,其余都是Java写的。
双亲委派机制执行的流程:
自低而上检查类是否已经加载,首先是CumtomClassLoader自定义类加载器有没有曾经加载过Student.class这个类,如果加载过直接返回,
如果没有加载过就委派给他的Parent就是AppClassLoader,看他有没有加载过这个类,如果也没有那么AppClassLoader又会
委派给ExtensionClassLoader,如果也没有就委派给最顶层的Bootstrap ClassLoader,  如果之前也没有加载过,那么Bootstrap ClassLoader
就会尝试去JRE\lib\rt.jar或者Xbootclasspath(可以指定位置)选项指定的jar包下面有没有要加载的Student.class这个类,如果发现了Class文件就
加载并返回,如果没有就会自顶向下委派给ExtensionClassLoader去到对应的目录看有没有对应的Class文件,这样一直往下,最后CustomClassLoader
自定义的ClassLoader会按照findClass的方式去寻找有没有对应Class文件的字节byte数组,如果有就直接装载到jvm中。
public class ClassLoaderTest {public static void main(String[] args) {//获取系统类加载器ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2//获取其上层:扩展类加载器ClassLoader extClassLoader = systemClassLoader.getParent();System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@45ee12a7//获取其上层:获取不到引导类加载器ClassLoader bootstrapClassLoader = extClassLoader.getParent();System.out.println(bootstrapClassLoader);//null//对于用户自定义类来说:默认使用系统类加载器进行加载ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2//String类使用引导类加载器进行加载的。---> Java的核心类库都是使用引导类加载器进行加载的。ClassLoader classLoader1 = String.class.getClassLoader();System.out.println(classLoader1);//null}
}

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@45ee12a7
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
* 我们尝试获取引导类加载器,获取到的值为 null ,这并不代表引导类加载器不存在, 因为引导类加载器右 C/C++ 语言,我们获取不到
* 两次获取系统类加载器的值都相同:sun.misc.Launcher$AppClassLoader@18b4aac2 ,这说明系统类加载器是全局唯一的
● 启动类加载器(引导类加载器,Bootstrap ClassLoader)
1. 这个类加载使用C/C++语言实现的,嵌套在JVM内部
2. 它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类
3. 并不继承自java.lang.ClassLoader,没有父加载器
4. 出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类
例如java.lang这个包,里面的类都是他负责加载的,通常这些核心类被签名,不能被替换掉。
● 扩展类加载器(Extension ClassLoader)
1. Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
2. 派生于ClassLoader类
3. 父类加载器为启动类加载器
4. 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。
如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载
应用程序类加载器(系统类加载器,AppClassLoader)
1. Java语言编写,由sun.misc.LaunchersAppClassLoader实现
2. 派生于ClassLoader类
3. 父类加载器为扩展类加载器
4. 它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库
5. 该类是程序中默认的类加载器,一般来说,项目中自己写的类由应用程序类加载器加载
6. 通过classLoader.getSystemclassLoader()方法可以获取到该类加载器

● 双亲委派机制优势:

● 案例 1 :代码:我们自己建立一个 java.lang.String 类,写上 static 代码块
案例2:在我们自己的 String 类中整个 main() 方法
● 案例 3 :在 java.lang 包下整个 Robot类
通过上面的例子,我们可以知道,双亲机制可以
1. 避免类的重复加载
2. 保护程序安全,防止核心API被随意篡改
    1) 自定义类:java.lang.String 没有用
    2) 自定义类:java.lang. Robot(报错:阻止创建 java.lang开头的类)
● 沙箱安全机制
1. 自定义String类时:在加载自定义String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar包中java.lang.String.class),报错信息说没有main方法,就是因为加载的是rt.jar包中的String类。
2. 这样可以保证对java核心源代码的保护,这就是沙箱安全机制。

JVM--类加载器详解相关推荐

  1. JVM 类加载器详解

    类加载器作用: 类加载器子系统作用: 1. 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识. 2. ClassLoader只负责class文件的加载 ...

  2. ccs加载out文件_类加载流程、类加载机制及自定义类加载器详解

    原文:juejin.im/post/5cffa528e51d4556da53d091 一.引言 当程序使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.链接.初始化三个步骤对该类进行类加载 ...

  3. Java class类文件和类加载器详解以及代码优化

    JVM就是Java虚拟机,它是Java程序运行的载体. 计算机只识别0和1.Java是⾼级语⾔.⾼级语⾔编写的程序要想被计算机执⾏,需要变成⼆进制形式的本地机器码.能直接变成机器码的语义是C++,它的 ...

  4. JVM类加载机制详解

    本文来详细说下JVM类加载机制 文章目录 概述 类加载器是什么 类加载的过程 加载 连接 初始化 类的主动引用和被动引用 主动引用 被动引用 三种类加载器 双亲委托机制 核心思想 源码分析 类的动态加 ...

  5. Java类加载器详解

    Java虚拟机中的类加载有三大步骤:,链接,初始化.其中加载是指查找字节流(也就是由Java编译器生成的class文件)并据此创建类的过程,这中间我们需要借助类加载器来查找字节流. Java虚拟机默认 ...

  6. Java高新技术第一篇:类加载器详解

    首先来了解一下字节码和class文件的区别: 我们知道,新建一个java对象的时候,JVM要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath(就是我们新建Java工程的 ...

  7. 类加载器源码、双亲委派、自定义类加载器详解

    文章目录 jdk的类加载器 双亲委派 自定义类加载器 打破双亲委派 jdk的类加载器 查看一个类的类加载器: ClassLoader classLoader = boy.class.getClassL ...

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

    2019独角兽企业重金招聘Python工程师标准>>> 首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1.什么是类加载?什么时候进行类加载? 2.什么是类初始化?什么时 ...

  9. 异常将上下文初始化事件发送到类的侦听器实例._Java CLassLoader类加载器详解,一点课堂(多岸学院)...

    Java CLassLoader 类加载器(class loader)是 Java™中的一个很重要的概念.类加载器负责加载 Java 类的字节代码到 Java 虚拟机中.本文首先详细介绍了 Java ...

  10. JVM类加载机制详解-20160812

    JVM类加载机制 一,类加载器体系     类加载器是沙箱的第一道防线,毕竟代码都是类加载器装入到JVM的.类加载体系通过使用不同的类加载器把类放 入不同的命名空间中,从而保护善意代码不受恶意代码的干 ...

最新文章

  1. OCP 12c最新考试原题及答案(071-3)
  2. IE相关的一些BUG汇总
  3. _variant_t和_bstr_t有什么区别
  4. 如何从零到一地开始机器学习?
  5. ubuntu优化服务器网络连接数,ubuntu下解决高并发socket最大连接数限制,tcp默认1024个连接...
  6. sas infile和filename
  7. 【OS学习笔记】十六 保护模式四:进入保护模式与在保护模式下访问内存的汇编代码
  8. 四十一,java中Annotation详解
  9. ASP连接各类数据库的语句
  10. 改写画质、突破性能, Unity 全面升级!
  11. 20200714每日一句
  12. 最近服务器总被webshell攻击,木马也非常猖獗
  13. BS架构与CS架构的区别(最详细)
  14. 如何获取地址栏的id (参数)
  15. 什么是Promise
  16. 山东理工ACM 1151 C语言实验——输出字符串
  17. android 最火框架,一个牛逼哄哄的Android框架One,秒杀最火的Xutils
  18. matlab中二维插值中cubic方法的实现原理(个人见解)
  19. Android studio 导出安卓APP软件方法
  20. 树莓派配置文件config.txt详细介绍

热门文章

  1. 双系统下ubuntu自动挂载windows盘
  2. 广州华夏职业学院计算机,牛!华夏学子被清华大学聘用!
  3. linux跳板,Linux基础-case -跳板主机
  4. 个人信息安全影响评估流程
  5. python快乐编程基础入门,列表与元组
  6. Linux入门和使用
  7. Win7 系统美化知识
  8. LabVIEW的第三方驱动(I/O接口设备)
  9. 六大维度让你彻底明白机器视觉与计算机视觉的区别!
  10. 年收入过10亿美元,Veeam看好云数据管理