JVM中的类加载

关于JVM中类的加载这部分知识在网上有太多的文章描述这部分的知识。但是多数文章都过于冗长,难以理解。这篇文章主要是一些我对JVM中类的加载的理解。

一、一句话概括

java在类加载的时候实际上就是把xxx.class文件读入JVM方法去,并在内存中生成class的对象。

二、那么Java中是怎么加载类的

1. 首先我们要了解类加载器

java 中有四种类加载器。从底向上依次是

  1. BootStrapClassLoader: 负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。
  2. ExtensionClassLoader: 负责加载 JAVA_HOME\lib\ext 目录中的,或通过java.ext.dirs系统变量指定路径中的类库。
  3. ApplicationClassLoader: 负责加载用户路径(classpath)上的类库。
  4. UserClassLoader:用户自定义的ClassLoader。

2. 类加载器是怎么加载类的

类加载器是通过双亲委派机制来加载类的

2.1 什么是双亲委派机制?

类加载器在接收到类加载请求之后,低等级的ClassLoader会首先检查这个类是否已经加载过了,若是没有加载则,将加载的请求委派给双亲(比如 ApplicationClassLoader会将请求委派给ExtensionClassLoader)。这样一层一层的传送直到BootStrapClassLoader,如果BootStrapClassLoader没有找到,则逐级向下反馈,下级再寻找该类试图加载。

2.2 为什么使用双亲委派机制?双亲委派机制的好处?

  • JVM只有在两个类的类名和加载它的类加载器均相同的情况下才会判定这两个类相同。若不采用双亲委派机制,则有可能造成一个类被多个不同的类加载器加载,这样会被识别为几个相互不同的类,相互之间赋值会出现问题。
  • 双亲委派机制能保证多加载器加载某个类时,最终都是由一个加载器加载,确保最终加载结果相同。

3. 类加载的过程中哪些代码会被执行到?

静态代码块以及静态变量 这些内容只被执行一次,因此他们在内容中的位置是相对固定的。所以被叫做静态。用这样的概念来解释静态变量:

  • 静态变量:是代码中用static关键字修饰,告诉JVM,该变量只在内存中存在一份,该引用存在方法区且地址是相对固定不变的所以称作“静态变量”。

三、类加载的具体过程

1. 加载(loading)

加载阶段主要完成的是将虚拟机外部的二进制字节流按照JVM所需的格式存储在方法区中。

  1. 通过一个全限定名获取二进制字节流。
  2. 将二进制中的静态存储结构转化为方法区的运行时数据结构。
  3. 在内存中生成一个代表这个类的Class对象,作为方法区数据的访问接口。

2.验证(verification)

验证作用是确保文件的字节流包含信息符合当前虚拟机要求,保证其并不会危害虚拟机的安全。
验证的主要内容为:

  1. 文件格式验证:
    这一步主要是保证Class文件格式上符合Java信息的要求。例如文件类型,版本号,常量池,常量池数据等等。
    注:在这一步字节流就会进入内存的方法区之中了,后面的操作都是基于方法区内的存储结构进行的。
  2. 元数据验证:
    对字节码描述信息进行语义分析,例如类是否有父类,重载是否正确,final,abstract有没有用错等,其主要目的是对类的元数据进行语义分析,保证符合Java语言规范。
  3. 字节码验证:
    对数据流和控制流进行分析。例如字节码指令集的正确,程序跳转的安全。其主要目的是检查方法体内的数据安全,确保程序语义合法,符合逻辑。
  4. 符号引用验证:
    符号引用验证也是一个比较特殊的阶段,其为解析阶段服务(这也验证了前面所说的,这几个过程并不是依次执行完成的)。在解析过程中,虚拟机将符号引用转换为直接引用,其主要是对常量池中的各种符号引用做匹配性校验。检验内容包括以下几个:

    • 符号引用指向的类能否找到。
    • 指定的类有没有描述的方法和字段。
    • 符号引用指向的各种信息的访问权限是不是对的。

3. 准备(preparation)

为类变量(被static修饰的变量)分配内存并设置类变量初始值。这里需要注意的是设初始值值得是为其设置零值,例如数值量的 0,boolean 值的 false 等。但是特殊情况下,如类变量是一个常量,那么在准备阶段,虚拟机就会将其设置为常量指代的值。

4. 解析 (resolution)

在验证阶段的符号引用验证说过解析阶段就是将符号引用转换为直接引用,那么符号引用和直接引用分别指什么呢,他们之间又有何区别:

  • 符号引用。是能够无歧义定位目标的任何形式的字面量,其与虚拟机实现的内存布局无关,引用的目标不一定需要加载入内存中;
  • 直接引用。可以直接指向目标指针,偏移量的引用,其和虚拟机实现的内存布局相关,引用的目标一定需要在内存中。

在这一步虚拟机会将类/接口,字段,类方法,接口方法等进行解析,变为直接引用。

5. 初始化(initialization)

初始化阶段主要是初始化类变量和其他资源,主要是通过()方法。
()是通过编译器自动收集所有类变量的赋值动作和静态语句块(static{}块)并按照顺序合并生成的。

5.1 什么时候JVM进行初始化?

  1. 在字节码层面遇到以下指令时,new(对象都要生成了,肯定要初始化了),get/put static(使用静态变量了,肯定要赋值了),invoke static(调用静态方法了都,肯定要为静态量赋值);
  2. 反射调用。当使用java。lang。reflect中的方法对类进行反射调用;
  3. 初始化一个类的时候,发现父类还有初始化,那么需要先初始化其父类,(父接口不用立即初始化,只有使用到其常量时,才需要将其初始化);
  4. 虚拟机需要一个入口,因此主类需要初始化;
  5. 动态方法解析,解析出方法是其他类的静态方法,那么需要将其初始化。

JVM中的类加载的更多相关文章

  1. Java面试题:JVM中的类加载机制

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

  2. Java中的类加载器以及Tomcat的类加载机制

    在加载阶段,虚拟机需要完成以下三件事情: 1.通过一个类的全限定名来获取其定义的二进制字节流. 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构. 3.在Java堆中生成一个代表这个类 ...

  3. jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解

    一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机:  1 ...

  4. JVM中类加载器的父委托机制

    类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap) 扩展类加载器(Extension) 系统类加载器 ...

  5. Java虚拟机JVM学习05 类加载器的父委托机制

    Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...

  6. Java中的类加载器

    转载:http://blog.csdn.net/zhangjg_blog/article/details/16102131 从java的动态性到类加载机制   我们知道,Java是一种动态语言.那么怎 ...

  7. tomcat 7 中的类加载器学习

    tomcat 7自带很多junit测试用例,可以帮助我们窥探源码的秘密.以下使用来测试类加载器的一个测试用例.类加载器也是对象,他们用来将类从类从.class文件加载到虚拟机,这些已经讲了很多,深入j ...

  8. 你需要简单了解JVM中的内存长什么样子

    下面有关JVM内存,说法错误的是? 1.程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,是线程隔离的 2.Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接 ...

  9. JVM学习之类加载

    该文使用Hotspot    JDK1.7 一.类加载器 1.什么是类加载器 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java ...

随机推荐

  1. linux环境下安装python 3

    说明: 在linux环境下,都默认安装python 2的环境,由于python3在python2的基础上升级较大,所以安装python 3环境用于使用最新的python 3的语法. 安装过程: 1.下 ...

  2. java https post请求并忽略证书,参数放在body中

    1 新建java类,作用是绕过证书用 package cn.smartercampus.core.util; import java.security.cert.CertificateExceptio ...

  3. win32 event事件

    原文地址:https://blog.csdn.net/u011394598/article/details/82981399 SetEvent/ResetEvent分别将EVENT置为这两种状态分别是 ...

  4. makefile那些事儿

    一.好处 自动化编译,一条make命令,整个工程可以完全自动编译,make命令是构建大型项目的首选方案. makefile就像一个shell脚本一样,用来定义规则,一个名称包含一条或多条命令,在终端m ...

  5. Mac系统Android 命令行签名

    jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore keystore文件位置 -signedjar ~/afterSign ...

  6. UE4 Animation]IK Related

    转自:https://dawnarc.com/2018/05/ue4animationik-related/ Examples 工程1 在油管上看到一个UE4 IK动画的demo工程示例 该示例作者的 ...

  7. odoo self.ensure_one()

    源码: def ensure_one(self): """ Verifies that the current recorset holds a single recor ...

  8. redis学习(二)——案例练习

    案例需求: 1.提供index.html页面,页面中有一个省份下拉列表 2.当页面加载完成后发送ajax请求,加载所有省份 3.列表中的省份保持不变,则之后每次刷新页面都是从redis中获取 * 注意 ...

  9. C++ STL学习总结

    1.vector //最好给它一个初始化大小 #include <iostream> #include <vector> using namespace std; int ma ...

  10. 类的练习——python编程从入门到实践

    9-1 餐馆:创建一个名为Restaurant的类,其方法__init__()设置两个属性:restaurant_name和cuisine_type.创建一个名为describe_restaurant ...