JVM类加载机制

JVM类加载机制

JVM类加载机制分为:加载,验证,准备,解析,初始化五步,如 下图:

JVM类加载机制
  • 加载:这个阶段会在内存中生成一个代表这个类的java.lang.Class对象作为方法区这个类的各种数据的入口。
  • 验证:目的去报Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机的自身安全。
  • 准备:该阶段为类变量分配内存并设置类变量的初始值,即在 方法区中分配这些变量所使用的内存空间。
  • 解析:指虚拟机将常量池中的符号引用替换为直接引用的过程(比如说方法的符号引用,是有方法名和相关描述符组成,在解析阶段,JVM把符号引用替换成一个指针,这个指针就是直接引用,它指向该类的该方法在方法区中的内存位置)
  • 初始化:为类的静态变量赋予正确的初始值。当静态变量的等号右边的值是一个常量表达式时,不会调用static代码块进行初始化。只有等号右边的值是一个运行时运算出来的值,才会调用static初始化.

以下几种情况不会执行初始化操作

  • 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化
  • 定义对象数组,不会触发该类的初始化
  • 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触
    发定义常量所在的类
  • 通过类名获取Class 对象,不会触发类的初始化
  • 通过Class.forName 加载指定类时,如果指定参数initialize 为false 时,也不会触发类初
    始化,其实这个参数是告诉虚拟机,是否要对类进行初始化
  • 通过ClassLoader 默认的loadClass 方法,也不会触发初始化动作

类加载器

JVM提供了三种类型的加载器

  • 启动类加载器:负责加载JAVA_HOME/lib目录中的,或者通过-Xbootclasspath参数指定路径中的,且被虚拟机认可的类
  • 扩展类加载器:负责加载 JAVA_HOME\lib\ext 目录中的,或通过java.ext.dirs 系统变量指定路径中的类
  • 应用程序类加载器:负责加载用户路径(classpath)上的类库。

JVM 通过双亲委派模型进行类的加载,当然我们也可以通过继承java.lang.ClassLoader
实现自定义的类加载器

JVM类加载机制
public class ClassLoaderMain {

    public static void main(String[] args) {
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

//当前的ClassLoader是AppClassLoder,其父ClassLoader是ExtClassLoader,祖父ClassLoader是根类装载器。java无法获取它的句柄,所以返回是null
        System.out.println("1  "+contextClassLoader);
        System.out.println("2  "+contextClassLoader.getParent());
        System.out.println("3  "+contextClassLoader.getParent().getParent());
    }

}

运行上面程序即可发现, 当前的ClassLoader是AppClassLoder,其父ClassLoader是ExtClassLoader,祖父ClassLoader是根类装载器。java无法获取它的句柄,所以返回是null 。

双亲委派

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的
Class),子类加载器才会尝试自己去加载.

采用双亲委派的一个好处是比如加载位于rt.jar 包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object 对象

ClassLoader的重要方法

  • Class LoadClass(String name):name参数指定类装载器需要装载类的名字,为全限定类名。如com.rookie.bigdata.reflect.Person。并且存在一个重载方法loadClass(String name,boolean resolve);resolve用来用来标识是否需要解析该类。在初始化之前,应考虑进行类解析工作,但并不是所有的类都需要解析。如果JVM只需要知道该类是否存在或者找出该类的超类,那么久不需要进行解析。
  • Class DefineClass(String name,byte[] b,int off,int len):将类文件的字节数组转换成JVM内部的java.lang,Class对象。字节数组可以从本地文件系统,远程网络中获取。参数name为字节数组对应的全限定类名。
  • Class findSystemClass(String name):从本地文件系统载入Class文件。该方法是JVM默认使用的装载机制。
  • Class findLoadedClass(String name):调用该方法来查看ClassLoader是否已装入某个类,如果已装入,那么返回java.lang.Class对象;否则返回null.

  • ClassLoader getParent():获取类装载器的父装载器,除根装载器外,所有的类装载器都有且仅有一个父装载器。ExtClassLoader的父装载器是根装载器,因为根装载器是非java语言编写,所以无法获得。

参考:https://segmentfault.com/a/1190000014395186

Original: https://www.cnblogs.com/haizhilangzi/p/12657665.html
Author: 海之浪子
Title: JVM类加载机制

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/581090/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 一个java swt桌面程序开发到打包的总结(1)(收集)

    –概述与关于swt的问题 转载自:http://www.cnblogs.com/overstep/tag/swt/ 一、概述: 几天一直在用金山打字通练习英语(本人英语…

    Java 2023年5月29日
    069
  • 使用Gradle构建Java项目

    使用Gradle构建Java项目 这个手册将通过一个简单的Java项目向大家介绍如何使用Gradle构建Java项目。 我们将要做什么? 我们将在这篇文档中创建一个简单的Java项…

    Java 2023年5月29日
    0129
  • 1.18(设计模式)状态模式

    状态模式:当对象状态改变时行为也随之改变,看起来就像是这个类发生了改变。 首先对象有状态,行为由状态决定。 假设现在有一个游戏角色,有正常状态、加速状态、减速状态、眩晕状态。 游戏…

    Java 2023年6月8日
    077
  • IO流

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月7日
    084
  • maven bug解决

    [ERROR] Failed to execute goal on project cloud-consumer-feign-order80: Could not resolve …

    Java 2023年6月15日
    0115
  • maven docker 插件集成的几个小坑

    昨晚看springboot视频的时候,发现可以使用docker-maven-plugin这个插件直接build出 docker 镜像到远程服务器上,感觉很方便,于是自己也试了一下,…

    Java 2023年6月16日
    075
  • WCF 返回json的时间格式的转换

    有朋友用这个办法不错 1、把”\/Date(976723200000+0800)\/”中的976723200000提取出来,这一步无论是正则还是substr…

    Java 2023年6月14日
    080
  • docker 安装mysql5.7

    拉取镜像 docker pull mysql:5.7 准备数据目录 mkdir -p /mall/docker/mysql/conf mkdir -p /mall/docker/m…

    Java 2023年6月9日
    052
  • 虚拟机栈的五道面试题

    虚拟机栈的五道面试题 1、举例栈溢出的情况?(StackOverFlowError) 通过-Xss设置栈的大小如果采用固定大小的java虚拟机栈,每一个线程的java虚拟机栈容量在…

    Java 2023年6月14日
    080
  • harbor安装

    Harbor 简介 Docker容器应用的开发和运行离不开可靠的镜像管理,虽然Docker官方也提供了公共的镜像仓库,但是从安全和效率等方面考虑,部署我们私有环境内的Registr…

    Java 2023年6月15日
    0108
  • Spring系列15:Environment抽象

    本文内容 Environment抽象的2个重要概念 @Profile 的使用 @PropertySource 的使用 Environment抽象的2个重要概念 Environmen…

    Java 2023年6月5日
    0122
  • ShenYu 网关开发:在本地启用运行

    1.先决条件 无论什么方式安装,都需要先初始化数据库,这里我选择了在本地通过 Docker 启用一个 mysql 5.7 docker run -d \ –name mysql …

    Java 2023年6月9日
    081
  • OutOfMemoryError异常

    除了程序计数器外,虚拟机内存在其他几个运行时区域都有发生OutOfMemoryError异常的可能。 Java堆溢出 设置Idea堆的大小为20MB,不可扩展(-Xms参数与最大值…

    Java 2023年6月9日
    088
  • Java源码赏析(一)Object 类

    写这个系列的原因,其实网上已经有无数源码分析的文章了,多一篇不多,少一篇不少,但为什么还要写这部分文章呢?于私,其一,上班族已经很久没有打过完整的一整段有意义的话,算是锻炼个人的书…

    Java 2023年6月8日
    074
  • Spring事务调用类自己方法失效解决办法和原因

    正常情况下,我们都是在controller里调用service里的方法,这个方法如果需要加事务,就在方法上加上@Transactional,这样是没问题的,事务会生效。 可是如果像…

    Java 2023年5月30日
    077
  • 【SpringCloud-Alibaba系列教程】7.容错

    一丶背景 在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个…

    Java 2023年6月5日
    086
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球