JVM 类加载

  • 1 JVM 类加载概述
  • 2类加载的基本流程
    • 2.1 加载(Loading)
    • 2.2 验证(Verification)
    • 2.3 准备(Preparation)
    • 2.4 解析(Resolution)
    • 2.5 初始化(Initialization)
    • 2.6 使用(Using)
  • 3 示例
  • 4 双亲委派模型
    • 4.1 概述
    • 4.2 三种类加载器
    • 4.3 三种类加载器执行说明
    • 4.4 双亲委派模型的优点

1 JVM 类加载概述

  Java 中的类加载是 JVM 中的一个非常核心的流程,其做的事情就是将 .class 文件转换成 JVM 中的对象, 例如我们发明了一个编程语言,那么肯定是想让这个编程语言跑起来, 那么这就需要把源代码编译成可执行程序,然后再去执行代码逻辑. 要想完成类加载,必须要明确的知道 .class 文件中都有啥,按照规则来进行解析,因此编译器和 JVM 类加载器必须要商量好 .class 文件的格式, 这个 .class 文件的格式是 Java 虚拟机规范文档里面约定的,其实就是一种"协议".关于 Java 虚拟机规范文档地址为: Java虚拟机规范文档.

2类加载的基本流程

  关于类加载的基本流程主要是从 .class 文件 => 内存类对象的过程,主要步骤如下:

2.1 加载(Loading)

 这里的加载阶段指的是整个类加载过程中的一个阶段, 这里千万不要与类加载混淆,一个是加载Loading,另一个是类加载 Class Loading; 首先将 .class 文件先找到, 代码中需要加载某个类,就需要在某个特定的目录中找到这个 .class 文件, 找到后打开这个文件并进行读取,此时就把这些数据读到了内存里面;总之,在加载 Loading 阶段, Java 虚拟机需要完成以下三件事情:
1) 通过一个类的全限定名来获取定义此类的二进制字节流;
2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
3) 在内存中生成一个代表这个类的 java.lang.Class 对象, 作为方法区这个类的各种数据的访问入口.

2.2 验证(Verification)

验证就是把刚才读到内存里的东西进行一个校验, 主要是验证一下刚才读到的这个内容是不是一个合法的 .class 文件, 必须是编译器生成的 .class 文件才能通过验证, 如果我们随便创建一个后缀名为 .class 文件是不能通过验证的; 并且这里除了验证文件格式之外,也会验证一下文件里面的一些字节码指令(方法里面具体要执行的指令)是否正确. 总之, 验证选项可以是文件格式验证, 字节码验证, 符号引用验证等.

2.3 准备(Preparation)

这里的准备阶段其实就是为了类对象中的一些成员分配内存空间, 并且进行一个初步的初始化操作, 也就是把初始空间设为全 0; 例如:

class Test {public static int value = 111;
}

类似于这句代码初始化 value 的 int 值为 0, 而不是111.

2.4 解析(Resolution)

  解析操作主要是针对字符串进行的处理, .class 文件中会涉及到一些字符串常量, 在这个类加载的过程中, 就需要把这些字符串常量给替换成当前 JVM 内部已经持有的字符串常量的地址. 也可以说解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程, 也就是初始化常量的过程. 这里需要注意的是: 并不是程序一启动, 就立即把所有的类都给加载了, 而是用到哪个类就加载哪个类, 但是呢字符串常量池是最初启动 JVM 就有的, 存在于堆中.

2.5 初始化(Initialization)

  这里的初始化才是对静态变量进行初始化, 同时也会执行 上面代码中 static 代码块. 也就是说 Java 虚拟机真正开始执行类中编写的 Java 程序代码, 将主导权移交给应用程序, 初始化阶段就是执行类构造器方法的过程.

2.6 使用(Using)

到这里其实已经加载完成了!!!

3 示例

class A {public A() {System.out.println("A 构造方法");}static {System.out.println("A static");}
}
class B extends A {public B() {System.out.println("B 构造方法");}static {System.out.println("B static");}
}public class TestJVM{public static void main(String[] args) {B b = new B();}
}

运行结果:

代码解读:
当 new B() 的时候,就先尝试加载 B 这个类. 然后加载 B 的时候发现 B 继承自 A, 于是又得先去加载 A, 两个类都加载完了再进行实例化操作, 构造方法是 new 对象的时候才调用, 此时已经初始化完成了; 口诀: 由父及子, 静态先行.

4 双亲委派模型

4.1 概述

  • 站在 Java 虚拟机的角度来看, 只存在两种不同的类加载器,: 一种是启动类加载器,这个类加载器由 C++ 来实现, 是虚拟机自身的一部分; 另外一种就是其他所有的类加载器, 这些类加载器都是由 Java 语言实现的, 独立存在于虚拟机外部, 并且全都继承自抽象类 java.lang.ClassLoader. 站在我们程序猿的角度, 类加载器就应该划分的更细致一些,自 JDK1.2以来, Java 一直保持这三层类加载器以及双亲委派的类加载器. 那么什么是双亲委派模型呢?
  • 如果一个类加载器收到了类加载的请求, 它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成, 每一个层次的类加载器都是如此, 因为所有的加载请求最终都应该传送到最顶层的启动类加载器中, 只有当父加载器反馈自己无法完成这个加载请求时,也就是在搜索范围内没有找到所需的类时,子加载器才会尝试自己去完成加载.
  • 在加载(Loading) 阶段, JVM 去哪个目录中来找 .class 这样的一个细节属于整个类加载过程中非常不起眼的一个环节, 但是这个环节却比较重要, 这是比较难以置信的, 可能是双亲委派模型这个名字比较霸气吧. 进行类加载过程中,一个比较重要的环节就是根据这个类的名字"java.lang.String"找到对应的 .class 文件, 在 JVM 中,有三个类加载器来负责进行这里找文件的操作, 这三个类加载器各有自己负责的区域.

4.2 三种类加载器

4.3 三种类加载器执行说明

执行步骤说明:

  • 这三个类加载器之间存在父子关系, 但是并不是继承里面的父类子类这样的关系, 而是像链表一样, 每个类里面都有一个 parent 字段, 指向了父类加载器.
  • 当在代码中使用到某个类的时候, 就会触发类加载器, 也就是说先从 AppClassLoader 开始, 但是 AppClassLoader 并不会真的开始去扫描自己负责的目录, 而是先去找其父类 ExtClassLoader, 但是 ExtClassLoader 也不会立即去扫描自己负责的目录, 而是也去找其父类加载器 BootStrap.
  • 到达 BootStrap 后, 也不会立即去扫描自己负责的目录, 也是先去找其父类加载器, 但是呢 BootStrap 上面已经没有了父类, 因此就去扫描自己负责的目录.
  • 如果在 BootStrap 中找到了需要的类, 就进行加载, 就没有其他类加载器的事情了, 但是如果没有匹配到合适的类, 就会告诉子加载器 ExtClassLoader, 再从 ExtClassLoader 所负责的目录中查找所需的类, 如果找到就加载, 如果未找到就去 AppClassLoader 所负责的目录区域查找类, 如果找到了就加载, 如果到这里还没有找到的话, 那就芭比Q了, 直接抛出 ClassNotFoundExcept 异常.

4.4 双亲委派模型的优点

1) 避免重复加载类: 例如 A 类和 B 类都有一个父类 C 类, 那么当启动 A 的时候就会将 C 类加载起来, 那么在 B 类进行加载时就不需要再重复加载 C 类了.
2) 安全性而言: 使用双亲委派模型也可以保证 Java 的核心 API 不会被篡改, 如果没有使用这种模型, 而是每个类加载器加载自己的话就会出现一些问题, 例如在编写一个成为 java.lang.Object 类的时候, 程序运行起来后系统就会出现多个不同的 Object 类, 而有些 Object 类又是用户自己提供的, 因此安全性就得不到保证了.
其实我们自己写的类加载器就不一定非得遵守双亲委派模型, 自己写的类加载器就是为了告诉程序去一些目录中找 .class, 例如 Tomcat webapps 里面就有很多类, 这些就是由 Tomcat 内部自己实现的类加载器来完成的, Tomcat 就没有遵循双亲委派模型.

JVM 系列(二) --- JVM 类加载的基本流程相关推荐

  1. Jvm 系列(二):Jvm 内存结构

    所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问 ...

  2. jvm系列(二):JVM内存结构

    所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问 ...

  3. Jvm 系列(八):Jvm 知识点总览

    对于Java程序员来讲,spring全家桶几乎可以搞定一切,spring全家桶便是精妙的招式,jvm就是内功心法很重要的一块,线上出现性能问题,jvm调优更是不可回避的问题.因此JVM基础知识对于高级 ...

  4. jvm系列(七):jvm调优-工具篇

    16年的时候花了一些时间整理了一些关于jvm的介绍文章,到现在回顾起来还是一些还没有补充全面,其中就包括如何利用工具来监控调优前后的性能变化.工具做为图形化界面来展示更能直观的发现问题,另一方面一些耗 ...

  5. jvm系列(八):jvm知识点总览-高级Java工程师面试必备

    在江湖中要练就绝世武功必须内外兼备,精妙的招式和深厚的内功,武功的基础是内功.对于武功低(就像江南七怪)的人,招式更重要,因为他们不能靠内功直接去伤人,只能靠招式,利刃上优势来取胜了,但是练到高手之后 ...

  6. jvm系列(八):jvm知识点总览

    在江湖中要练就绝世武功必须内外兼备,精妙的招式和深厚的内功,武功的基础是内功.对于武功低(就像江南七怪)的人,招式更重要,因为他们不能靠内功直接去伤人,只能靠招式,利刃上优势来取胜了,但是练到高手之后 ...

  7. jvm系列二:Java8内存模型-永久代(PermGen)和元空间(Metaspace)

    原文地址:https://www.cnblogs.com/paddix/p/5309550.html 一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地 ...

  8. 「JVM 系列」- JVM的类加载机制

    前言 在类的生命周期中,第一个阶段是就是类的加载阶段,在这个阶段,非数组类的二进制字节流被加载进内存中,并生成一个java.lang.Class对象. 本文主要论述发生在这一阶段的故事. 一. 类加载 ...

  9. jvm十二:自定义类加载器

    package com.atChina.jvm;import java.io.*;public class Test16 extends ClassLoader{private String clas ...

最新文章

  1. CentOS 5.2 下安装tripwire2.3.1.2出错解决
  2. python朗读网页-早上起床后不想动,让 Python 来帮你朗读网页吧
  3. Web browser的发展演变
  4. HALCON示例程序measure_metal_part_first_example.hdev通过拟合边缘进行尺寸测量
  5. oracle between and monday,oracle——时间
  6. 拼音输入法功能大比拼
  7. windows驱动开发学习
  8. 西门子em235模块的功能_图文讲解PLC模拟量模块与传感器接线方法和注意事项
  9. java解释器怎么写_Java解释器和编译器
  10. tms intraweb html5,TMS VCL Chart
  11. SoapUI接口测试-基本操作
  12. 同济大学计算机学硕无人录取,2019年双非上岸同济大学计算机考研初复试经验分享,超详细!...
  13. Android原生支持组件编译,从0开始编译android类原生系统
  14. VTK学习笔记(十九)vtk polydata
  15. msxml6 x86.msi v6.10.1129.0
  16. Spring Boot基础学习08 - Spring Boot整合Redis
  17. 文化传媒婚纱摄影类网站织梦模板免费下载
  18. 番外7林芝·救赎之旅的最后一站——混合现实科幻《地与光》
  19. 买卖二手3C成了“拆盲盒”,究竟是谁之责?
  20. 3-24 浅谈多元正态分布的基本性质

热门文章

  1. 楚乔传手游 服务器维护,《楚乔传》退市公告
  2. Python 一键打开多个应用(非常简单)
  3. html中单击按钮事件,处理C++代码中的HTML按钮单击事件
  4. Webflux获取参数
  5. 世上从不缺少美 只需发现美的眼睛
  6. SQL函数的自定义和调用
  7. html multipart/form-data,(转载)multipart/form-data文件上传
  8. 深度揭开阿里(蚂蚁金服)技术面试流程 附前期准备,学习方向
  9. react h5 自定义数字+大写字母键盘
  10. Java修饰符和关键字