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. H5+js调用相机

    在机缘巧合之下,了解到用HTML5和javascript调用摄像头来实现拍照功能,今天就把大致原理写下来.页面布局很简单,就是一个input标签,两个HTML5元素video.canvas和一个but ...

  2. Java13新特性 -- 新增 移除 废弃 已知问题等

    新增 添加FileSystems.newFileSystem(Path, Map<String, ?>) Method 新的java.nio.ByteBuffer Bulk get/put ...

  3. VC 获取系统特殊文件夹的路径如:系统目录,桌面等

    转载:https://blog.csdn.net/qq_23992597/article/details/50963343 如果需要,请在StdAfx.h中添加 #include <shlobj ...

  4. 从原理到应用,Elasticsearch详解

    简介 Elasticsearch(简称ES)是一个分布式.可扩展.实时的搜索与数据分析引擎.ES不仅仅只是全文搜索,还支持结构化搜索.数据分析.复杂的语言处理.地理位置和对象间关联关系等. ES的底层 ...

  5. Houdini Mac 添加external editor

     我的尝试: 1. 找到houdini.env文件 2. 修改env文件,添加 EDITOR = ""/Applications/Sublime Text.app/Contents ...

  6. API设计之道

    接口安全要求: 1.防伪装攻击(案例:在公共网络环境中,第三方 有意或恶意 的调用我们的接口) 2.防篡改攻击(案例:在公共网络环境中,请求头/查询字符串/内容 在传输过程被修改) 3.防重放攻击(案 ...

  7. Linux下配置Golang开发环境

    前几天无意间看到了微信推送的golang开发的消息,看到golang那么牛逼,突然心血来潮想学习一下go.工欲善其事必先利其器,想做go开发,必须先配置好go的开发环境(就像开发Java先安装配置jd ...

  8. 浅谈Javascript 浅拷贝和深拷贝的理解

    javascript中存储对象都是存地址的. 浅拷贝:浅拷贝是都指向同一块内存区块,浅拷贝共用同一内存地址,你改值我也变.如果拷贝的对象里面的值是一个对象或者数组,它就是浅拷贝,拷贝的知识引用地址.  ...

  9. Java 注解基本原理

    原文地址 注解的本质 「java.lang.annotation.Annotation」接口中有这么一句话,用来描述『注解』. The common interface extended by all ...

  10. XGBoost中参数调整的完整指南(包含Python中的代码)

    (搬运)XGBoost中参数调整的完整指南(包含Python中的代码) AARSHAY JAIN, 2016年3月1日     介绍 如果事情不适合预测建模,请使用XGboost.XGBoost算法已 ...