JVM分析之类加载机制详解

目录
  • 1、前言
  • 2、类加载是什么
  • 3、类加载过程
    • 3.1 加载
    • 3.2 链接
    • 3.3 初始化
  • 4、总结

1、前言

JVM内部架构包含类加载器、内存区域、执行引擎等。日常开发中,我们编写的java文件被编译成class文件后,jvm会进行加载并运行使用类。本次仅对JVM加载部分进行分析,了解并掌握加载机制。

2、类加载是什么

类加载是一种过程,是将class文件加载到jvm内存的过程。当代码逻辑中需要引用类时,通过类加载器加载引用类对象并存放堆中,以供代码调用。

3、类加载过程

注:类加载过程包含 加载、链接(验证、准备、解析)、初始化

3.1 加载

加载:将类的class字节码文件读到内存,将其存放到运行时数据区的方法区,然后在堆区生成class对象,封装类在方法区内的数据结构。(方法区-》数据结构,堆区-》class对象)

过程:java文件-》通过java c编译成字节码.class文件-》引导类加载器(装载核心类库)-》扩展类加载器(将指定目录jar包装载至工作库)-》系统类加载器(将指定目录的类和jar包装载至工作库,常用)-》自定义类加载器(实现加载指定类或自定义加密等操作)

缓存:类加载到jvm后,会缓存一段时间(不管是否被引用),待jvm执行垃圾回收时才会回收未使用的缓存类,释放空间。

类加载器:

  • 启动类加载器:Bootstrap ClassLoader由C/C++实现,嵌套在JVM中,java程序无法直接操作;负责加载Java核心类库($JAVA_HOME中jre/lib目录下或-Xbootclasspath参数指定的路径目录下,如java.*开头的类)的class文件。
  • 扩展类加载器:Extension ClassLoader由Java编写,由sun.misc.Launcher$ExtClassLoader实现。加载java平台扩展的jar包,负责加载(java.ext.dirs目录或$JAVA_HOMEjre/lib/ext目录,如javax.开头的类)的class文件。
  • 应用程序类加载器:Application ClassLoader由Java编写,由sun.misc.Launcher$AppClassLoader实现。负责加载用户类路径(classpath)的class文件,java程序一般默认使用应用程序类加载器。
  • 自定义类加载器:一般情况下java程序使用上面三种类加载器就满足了,一些特殊情况下,我们需要自定义加载指定路径的类时,就需要继承java.lang.ClassLoader类,重写find Class或loadClass均可实现。(类隔离实践中就采用此方案)

类加载机制

  • 全盘负责:当加载器加载某个class时,该class所引用的其他class也一并被加载(自定义加载class除外);
  • 缓存机制:所有加载过的class均被缓存,当程序中使用某个class时,优先从缓存区中获取,如果缓存区不存在,才会读取该class的字节码文件,加载为class对象,并存入缓存区,以便后续使用。(修改class后,需要重启jvm才会生效)
  • 双亲委派:是一种类加载安全机制,当类加载器需要加载某个class文件时,会优先把加载委托给父类加载器处理,如果加载成功则返回,否则继续向上委托直至最顶层类加载器,当父类加载器在加载范围内均没有找到所需class文件,即表示无法完成加载,此时子加载器才会去加载。(先向上委托父类加载器处理,都失败后在自己再加载)
  • 反向委派:主要是用于第三方包加载,第三方包的类不在jdk/lib目录,所以Bootstrap ClassLoader引导类加载器无法直接加载SPI(Service Provider Interface,服务提供者接口)的实现类,双亲委派机制中定义无法反向委托Application Classloader系统加载器加载,因此需要一种特殊的ContextClassLoader线程上下文类加载器来加载第三方的类库。(*** 此处SPI接口后续文章分析 ***)

加载实现方式

 /*
  * 类加载方式
  * 1、类加载器,此方式加载的class对象还没有完成链接阶段
  * 2、java.lang.Class,此方式加载的class对象是完成初始化的
  * */
 ClassLoader classLoader = ClassSegregationTest.class.getClassLoader();
 classLoader.loadClass("com.lgy.example.class_segregation.SegregationTestA");
 // 默认初始化class对象
 Class.forName("com.lgy.example.class_segregation.SegregationTestA");
 // 默认不初始化,并且指定类加载器进行加载
 Class.forName("com.lgy.example.class_segregation.SegregationTestA", false, classLoader);

3.2 链接

链接是将java二进制代码合并至jvm运行的过程。

链接过程可分为 验证、准备、解析 三个阶段。

验证

保证正确加载类,包括文件格式验证(Class文件格式的规范)、元数据验证(Java语言规范)、字节码验证(通过数据流和控制流分析)、符号引用验证。

准备

  • 在方法区为静态变量(static修饰)分配内存,并设置类变量初始值(通常是数据类型默认的零值,如0,0L,null,false等)。
  • 显示赋值是在类对象实例化时处理(即 public static int x=10,准备阶段初始值为0,在对象实例化时,才被赋值10)

解析

  • 虚拟机中将常量池的符号引用(常量名)替换为直接引用(目标的指针地址)的过程;
  • 符号引用的目标不一定在内存中,但常量名(或称字面量)是明确定义在jvm规范的class文件格式中。
  • 直接引用是指向目标的指针地址、相对偏移量或间接定位到目标的句柄,是肯定在内存中。

3.3 初始化

执行每个类的构造方法init()的过程,init()方法是java编译器自动收集、合并所有类变量的赋值动作和静态代码块语句,完成初始化。

初始化步骤

  • 类未被加载或链接,则程序先加载并链接该类
  • 优先初始化直接父类,再执行子类初始化
  • 依次执行类中的初始化语句

初始化条件(只有对类主动使用时才会初始化类)

  • 创建类实例(new Class)
  • 类或接口静态变量的引用或赋值
  • 类静态方法的调用
  • 反射加载(Class.forName(''))
  • 子类被初始化,其父类也会被初始化
  • jvm启动时被标记启动类的类,或直接java.exe命令运行指定类

演示代码如下:

 /**
 * 定义父类与子类
 */
 class Parent {
  public static int a = 10;
  static {
   System.out.println(" 父类初始化 ");
  }
 }
 class Children extends Parent{
  public static int a = 100;
  static {
   System.out.println(" 子类初始化 ");
  }
 }
 public static void main(String[] args) throws Exception {
  // 子类没有定义变量a ( public static int a = 100;)
    System.out.println(Children.a); // 输出 --  父类初始化 -- 10 
    // 主动调用时才会执行类的静态块
    -----------------------------------------
    // 子类定义变量a 
    System.out.println(Children.a); // 输出 -- 父类初始化 -- 子类初始化  -- 100 
  // 子类被初始化时,优先初始化父类,所以父类静态块执行;调用变量a属于子类定义,属于主动调用,所以子类静态块执行
 }

调试输出加载对象(VM options 中添加 -XX:+TraceClassLoading

  • [Loaded com.lgy.example.class_segregation.Parent from file:/E:/dataway-demo/example/target/classes/]
  • [Loaded com.lgy.example.class_segregation.Children from file:/E:/dataway-demo/example/target/classes/]

仅在首次主动使用才会被初始化。

4、总结

以上就是关于自定义类加载器、加载过程的全部内容。

本文是针对于类隔离实现之自定义类加载器的扩展,对于应用中类加载阶段的进一步分析。

通过本文的分析可以了解到类加载过程及涉及到的jvm中的模块,在整理过程中发现有些细节还需要扩展,所以还尚未成功,还需持续跟进。

到此这篇关于JVM分析之类加载机制详解的文章就介绍到这了,更多相关JVM类加载机制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详细分析JVM类加载机制

    目录 前言 1. jvm 的组成 2. 类加载 1. 加载 2. 链接 3. 初始化 3. 类加载器 引导类加载器(启动类加载器) 扩展类加载器 应用程序类加载器 4. 双亲委派机制 5. 类的主动/被动使用 结语 前言 ladies and gentleman , 你们好 ,我是羡羡 , 这节我们进入jvm的学习 , 我们知道 , jvm是java虚拟机, java代码的执行与 jvm 息息相关, 接下来我们来依次介绍 , 首先这节先来介绍 jvm 中的类加载部分 1. jvm 的组成 jvm

  • Java JVM类加载机制解读

    目录 1.什么是类加载 2.类加载的过程 2.1加载 2.2验证 2.3准备 2.4解析 2.5初始化[重中之重之重中重] 第一段代码: 第二段代码: 第三段代码: 最后一段代码: 总结 1.什么是类加载 首先你要知道一个类的从被加载到虚拟机内存中开始,到被初始化为止,是为类加载的整个过程.下图就是类加载的整个过程: 一个类只有经历了加载.验证.准备.解析.初始化这五个关卡才能被认为是实现了类加载.这,就是类加载. 注意一点:上面五个过程并不是按部就班地"完成",而是按部就班地&quo

  • JVM的类加载过程详细说明

    一.基础知识 我们平时写的Java写代码一般都是.java文件,编译成为.class字节码文件,然后类加载器把.class文件加载到JVM内存中,接下来JVM就执行我们的字节码文件,整个过程就是这样. 画个图方便大家好理解: 类加载过程其实非常琐碎且复杂,但是我们只要把握其中的核心工作原理即可 一个类从加载到使用会经历以下步骤: 加载-〉验证-〉准备-〉解析-〉初始化-〉使用-〉卸载 以以下ClassLoadDemo类代码举例: /** * @author god-jiang * @date 2

  • 深入理解JVM之类加载机制详解

    本文实例讲述了深入理解JVM之类加载机制.分享给大家供大家参考,具体如下: 概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 与那些在编译时需要进行链接工作的语言不同,在Java语言里,类型的加载.连接和初始化过程都是在程序运行期间完成的,例如import java.util.*下面包含很多类,但是,在程序运行的时候,虚拟机只会加载哪些我们程序需要的类.这种策略虽然会令类加载时稍微增加

  • jvm虚拟机类加载机制详解

    目录 1 概述 2 类的加载时机 3 类的加载过程 3.1 加载 3.2 验证 3.3 准备 3.4 解析 3.5 初始化 4 类加载器 4.1 双亲委派模型 4.2 破坏双亲委派模型 1 概述 ​ Java虚拟机把描述类的数据从Class文件加载到内存, 并对数据进行校验.转化解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程称为虚拟机的类加载机制.在Java语言中,类型的加载.连接和初始化都是在程序运行期间完成的. 2 类的加载时机 ​ 一个类型从被加载到虚拟机内存中开始,到

  • 通俗讲解JVM的类加载机制

    前言 我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢. 如果懂得了JVM的运行原理和内存模型,像是一些JVM调优.垃圾回收机制等等的问题我们才能有一个更清晰的概念. 为了走进JVM,深入了解底层,王子打算写一个JVM的专题,留下自己对JVM探索的足迹,同时也希望能帮到小伙伴们更好的理解JVM. 那我们开始吧. JAVA代码的运行流程 首先我们就来聊一聊JAVA代码是怎么运行起来的,这部分比较基础相信大家都知道,就当成是个复习吧. 我们编写

  • JVM分析之类加载机制详解

    目录 1.前言 2.类加载是什么 3.类加载过程 3.1 加载 3.2 链接 3.3 初始化 4.总结 1.前言 JVM内部架构包含类加载器.内存区域.执行引擎等.日常开发中,我们编写的java文件被编译成class文件后,jvm会进行加载并运行使用类.本次仅对JVM加载部分进行分析,了解并掌握加载机制. 2.类加载是什么 类加载是一种过程,是将class文件加载到jvm内存的过程.当代码逻辑中需要引用类时,通过类加载器加载引用类对象并存放堆中,以供代码调用. 3.类加载过程 注:类加载过程包含

  • JVM类加载机制详解

    一.先看看编写出的代码的执行过程: 二.研究类加载机制的意义 从上图可以看出,类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性. 三.类加载的一般过程 原理:双亲委托模式 1.寻找jre目录,寻找jvm.dll,并初始化JVM: 2.产生一个Bootstrap Loader(启动类加载器): 3.Bootstrap Loader自动加载E

  • 面试必时必问的JVM 类加载机制详解

    目录 前言 正文 1.类加载的过程. 1)加载 2)验证 3)准备 4)解析 5)初始化 2.Java 虚拟机中有哪些类加载器? 1)启动类加载器(Bootstrap ClassLoader): 2)扩展类加载器(Extension ClassLoader): 3)应用程序类加载器(Application ClassLoader): 3.什么是双亲委派模型? 4.为什么使用双亲委派模式? 5.有哪些场景破坏了双亲委派模型? 6.为什么要破坏双亲委派模型? 7.如何破坏双亲委派模型? 8.Tomc

  • JVM核心教程之JVM运行与类加载全过程详解

    为什么要使用类加载器? Java语言里,类加载都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会给java应用程序提供高度的灵活性.例如: 1.编写一个面向接口的应用程序,可能等到运行时再指定其实现的子类: 2.用户可以自定义一个类加载器,让程序在运行时从网络或其他地方加载一个二进制流作为程序代码的一部分:(这个是Android插件化,动态安装更新apk的基础) 为什么研究类加载全过程? 有助于连接JVM运行过程 更深入了解java动态性(解热部署,动态加载),提高程

  • Java运行时环境之ClassLoader类加载机制详解

    背景:听说ClassLoader类加载机制是进入BAT的必经之路. ClassLoader总述: 普通的Java开发其实用到ClassLoader的地方并不多,但是理解透彻ClassLoader类的加载机制,无论是对我们编写更高效的代码还是进BAT都大有裨益:而从"黄埔军校"出来的我对ClassLoader的理解都是借鉴了很多书籍和博客,站在了各大博主的肩膀上,感谢你们!上菜,Classloader最主要的作用就是将Java字节码文件(后缀为.class)加载到JVM中,JVM在启动时

  • JVM的垃圾回收机制详解和调优

    文章来源:matrix.org.cn 作者:ginger547 1.JVM的gc概述 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作. 在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能.有些垃圾收集专用于特殊的应用程序.比如,实时应用程序主要是为了避免垃圾收集中断,而大多数OLTP应用程序则注重整体效率.理解了应用程序的工作负荷

  • java中类加载与双亲委派机制详解

    目录 类加载是什么 类加载器 双亲委派机制 BootStrapClassLoader ExtClassLoader AppClassLoader 为什么使用双亲委派机制 全盘负责委托机制 自定义类加载器 打破双亲委派机制 类加载是什么 把磁盘中的java文件加载到内存中的过程叫做类加载 当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把主类加载到JVM. 有如下 User 类 package dc.dccmmtop; public Class User { publi

  • Java SpringMVC拦截器与异常处理机制详解分析

    目录 拦截器(interceptor)的作用 拦截器快速入门 案例:用户登录权限控制 拦截器方法说明 SpringMVC异常处理 异常处理的思路 异常处理两种方式 拦截器(interceptor)的作用 Spring MVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理. 将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain).在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用.拦截器也是AOP思

随机推荐