`
海浪儿
  • 浏览: 274102 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

jvm学习笔记2--虚拟机类加载机制

    博客分类:
  • jvm
 
阅读更多

虚拟机类加载机制

 

  1. 生命周期
  • 从被加载到虚拟机内存,到卸载内存为止,包含7个阶段:加载  、验证解析 准备初始化使用卸载。

 

  • 验证、准备和解析统称为连接。
  •  加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,而解析则不一定,它可以在初始化阶段之后再开始,以支持java的运行时绑定。

2.  3种情况必须对类进行“初始化”

  • 遇到new(实例化对象)、getstatic(读取类静态字段)、putstatic(设置类静态字段)、invokestatic(调用类静态方法)这4条字节码指令
  • 使用Java.lang.reflect包对类进行反射调用
  • 当初始化一个类时,如果父类没有初始化,则对父类初始化
  • 注意点: 
  1.  
    1. 对于静态字段,只有直接定义该字段的类才被初始化,通过子类引用父类的静态字段,不会触发子类的初始化,只对父类初始化
    2. 通过数组定义来引用类,不会触发引用类的初始化
    3. final修饰的静态常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化;

 

3. 类加载的过程

  • 加载
  1.  
    1. 通过类的全限定名获取定义此类的二进制字节流;
    2. 将字节流代表的静态存储结构转化为方法区的运行时数据结构;
    3. Java堆中生成Java.lang.Class对象,作为方法区这些数据的访问入口
  • 验证
  1.  
    1. 目的:确保Class文件的字节流中包含的信息符合当前虚拟机的要求
    2. 4个阶段的校验过程:

1)文件格式验证:譬如是否以魔数0xCAFEBABY开头、主次版本号是否在当前虚拟机处理范围内等。该阶段基于字节流进行,经过该阶段后,字节流才会存储到内存的方法区中。

2)元数据验证:对字节码描述的信息进行语义分析,以保证信息符合Java规范的要求,譬如是否有父类(除了object类之外,所以的类都应该有父类)、是否继承了不允许被继承的类(被final修饰的类)等;

3)字节码验证:保证被校验类的方法在运行时不会做出危害虚拟机安全的行为,譬如保证跳转指令不会跳转到方法体以外的字节码指令上,方法体中的类型转换是有效的等。

4)符号引用验证:该动作在解析阶段发生。可以看做是对类自身以外(常量池中的各种符号引用)的信息进行匹配性的校验,目的是确保解析动作能正常执行。譬如符号引用中通过字符串全限定名是否能找到对应的类,符号引用中的类、字段、方法的访问性是否可被当前类访问等。一般会抛出java.lang.IllegalAccessErrorjava.lang.NoSuchFieldErrorjava.langNoSuchMethodError等异常。

  • 准备
  1.  
    1. 目的:为类变量分配内存并设置类变量的初始值;
    2. 内存都在方法区进行分配,进行内存分配的仅包含类变量(static修饰的),不包含实例变量
    3. 初始值是指数据类型的零值,譬如:

Public static int value = 123;

准备阶段后的初始值为0,而不是123.

注意:如果是常量(被final修饰),

Public static final int value = 123;

准备阶段后的初始值为123

  • 解析
  1.  
    1. 目的:将常量池中的符号引用替换为直接引用。
    2.  解析发生的时间:在执行anewarraycheckcastgetfieldgetstaticinstanceofinvokeinterfaceinvokespecialinvokestaticinvokevitualmultianewarraynewputfieldputstatic13用于操作符号引用的字节码指令之前
    3. 解析过程

1)类或接口的解析:

假设当前代码所处的类为DD的常量池中有一个从未解析过得符号引用N,将N解析为一个类或接口C的直接引用,过程如下: 

  •  
    •  
      • 如果C不是数组类型:将N的全限定名传递给D的类加载器去加载C。如果加载过程出现异常,则解析失败
      • 如果C是数组类型,且数组类型的元素类型为对象,即N的描述符是“[Ljava.lang.Integer”的形式:按照第1点加载Integer,接着由虚拟机生成一个代表此数组维度和元素的数组对象;
      • 如果上面步骤没出异常,则C在虚拟机中已经成为一个有效的类或接口了,但在解析完成之前,还需要进行符号引用验证,确认D是否具备对C的访问权限,否则抛出java.lang.IllegalAccessError异常。

2)字段解析

  •  
    •  
      • 首先对字段表内class_index项索引的CONSTANT_Class_info符号引用进行解析,即解析字段所属的类或接口的符号引用,用C表示
      • 然后对C进行字段搜索: 
  1.  
    1.  
      1.  
        1. 如果C本身包含了简单名称和字段描述符都与目标匹配的字段,则返回该字段的直接引用,查找结束
        2. 否则,如果C实现了接口,则按继承关系从上往下搜索各个接口和他的父接口。如果接口中包含了简单名称和字段描述符都与目标匹配的字段,则返回该字段的直接引用,查找结束
        3. 否则,按继承关系从上往下搜索其父类。如果父类中包含了简单名称和字段描述符都与目标匹配的字段,则返回该字段的直接引用,查找结束
        4. 否则,查找失败,抛出java.lang.NoSuchFieldError异常。
        5. 如果查找过程成功返回应用,则还需要对该字段进行权限验证,不通过,则抛出java.lang.IllegalAccessError异常

3) 类方法解析

4) 接口方法解析

注:后两者类似于字段解析

  • 初始化   
  1.  
    1. 该阶段才真正开始执行类中定义的Java代码(字节码)
    2. 执行类构造器<clinit>()方法:

 1) <clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的

2) <clinit>()方法与实例构造器(<init>()方法)不同,它不需要显示的调用父类构造器,虚拟机会保证在子类的<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕。(因此虚拟机中第一个执行的<clinit>()方法的类肯定是java.langObject

3) <clinit>()方法不是必须的,如果一个类没有静态语句块,也没有对变量的赋值动作,那么编译器可以不为这个类生成<clinit>()方法

4)接口可以有变量初始化的赋值动作,因此接口也会生成<clinit>()方法。但与类不同的是,不需要先执行父接口的<clinit>()方法,只有当父接口中定义的变量被使用时,父接口才被初始化。另外,接口的实现类在初始化时也一样不会执行接口的<clinit>()方法。

5)虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确的加锁和同步。

 

4. 类加载器 

  •  对于任意一个类,都需要由加载它的类加载器和这个类本身一同确定其在Java虚拟机中的唯一性。
  • 三种类加载器: 
  1.  
    1. 启动类加载器(Bootstrap ClassLoader):负责将存放在<JAVA_HOME>\lib目录中的,或被-Xbootclasspath参数所指定的路径中的,且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接使用。
    2. 扩展类加载器(Extension ClassLoader:sun.misc.Launcher$ExtClassLoader实现负责加载<JAVA_HOME>\lib\ext目录中的,或者被Java.ext.dirs系统变量所指定路径中的所有类库;可以直接使用扩展类加载器
    3. 应用程序类加载器(Application ClassLoader):sun.misc.Launcher$AppClassLoader实现负责加载用户类路径上(ClassPath)所指定的类库;一般作为默认的类加载器

注意:类加载器之间的父子关系不以继承来实现,使用组合来复用父加载器的代码

  •    双亲委派模型:

如果一个类加载器收到了类加载的请求,首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。

  • 定义自己的类加载器时,建议把自己的类加载逻辑写到findClass()方法中,而不是去覆盖loadClass()方法。

 

注:本笔记主要参考:深入理解Java虚拟机--Jvm高级特性与最佳实践一书及网络资料

分享到:
评论

相关推荐

    JVM 学习笔记(Java虚拟机)

    **JVM学习笔记(Java虚拟机)** Java虚拟机(JVM)是Java语言的核心组成部分,它是Java程序运行的平台,负责解释和执行字节码。深入理解JVM对于优化Java应用程序性能至关重要。本笔记将从以下几个方面详细介绍JVM:...

    jvm学习笔记(jvm内存模型&垃圾收集算法&类加载机制)

    在JVM的学习中,理解其内存模型、垃圾收集算法以及类加载机制至关重要。 1. **JVM内存模型** - **方法区**:也称为“永久代”,存储虚拟机加载的类信息、常量、静态变量等,是线程共享的区域。在Java 8之后,这...

    深入Java虚拟机JVM类加载学习笔记

    ### 深入Java虚拟机JVM类加载学习笔记 #### 一、Classloader机制解析 在Java虚拟机(JVM)中,类加载器(ClassLoader)是负责将类的`.class`文件加载到内存中的重要组件。理解类加载器的工作原理对于深入掌握JVM以及...

    Java虚拟机JVM类加载学习笔记

    Java虚拟机(JVM)是Java程序的核心组成部分,它负责执行字节码并...理解JVM的类加载机制对于优化程序性能、解决类加载问题以及深入学习Java运行机制至关重要。开发者应当掌握这些概念,以便更好地编写和调试Java代码。

    黑马程序员------类加载器学习注意点

    在Java编程语言中,类加载器(ClassLoader)是至关重要的组成部分,它负责将类的字节码从磁盘、网络或其他存储介质加载到JVM(Java虚拟机)中,并将其转换为可执行的Java对象。类加载器的学习是深入理解Java运行机制...

    java之jvm学习笔记五(实践写自己的类装载器)

    这个“java之jvm学习笔记五(实践写自己的类装载器)”很可能是对这一主题的详细探讨。 类装载器在Java中的主要职责是动态加载类到JVM中。Java的类装载器分为三个基本层次:启动类装载器(Bootstrap ClassLoader)、...

    JVM学习笔记.docx

    本篇JVM学习笔记主要涵盖了以下几个核心知识点: 1. **运行时数据区**: - **程序计数器**:记录当前线程执行的字节码的行号,用于线程恢复执行时跳转到正确位置。 - **Java虚拟机栈**:每个方法执行时创建的栈帧...

    java之jvm学习笔记十一(访问控制器)-源码

    本文将深入探讨JVM中的访问控制器,主要基于“java之jvm学习笔记十一(访问控制器)-源码”这一主题,以及相关的源码分析。 首先,我们得了解Java的安全模型。Java安全模型基于一种称为安全管理器(SecurityManager)...

    jVM学习笔记.ppt

    这一过程涉及到类加载机制,包括Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader和Custom ClassLoader,它们按照特定的层次关系和加载顺序加载类,确保类的唯一性。 类执行机制中,JVM基于栈的架构...

    jvm视频及笔记

    2. **类装载机制**:包括加载、验证、准备、解析和初始化五个阶段,确保类的正确性和安全性。 3. **内存模型**:包括堆内存、栈内存、方法区(在Java 8之后变为元空间)、程序计数器、本地方法栈等,理解它们的作用...

    Java 虚拟机学习笔记:Java 内存区域,垃圾收集,内存分配与回收策略,JVM 调优,文件结构,类加载机制,Java 程序

    Java 虚拟机学习笔记: Java 内存区域, 垃圾收集, 内存分配与回收策略, JVM 调优, 文件结构, 类加载机制, Java 程序 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的语言,...

    JVM:深入理解Java虚拟机 - 学习笔记

    2. **类加载机制** 类加载器负责查找并加载类文件,包括启动类加载器、扩展类加载器和应用程序类加载器。双亲委派模型确保了类加载的安全性和有序性。 3. **运行时数据区** JVM在运行过程中会划分多个区域,如堆...

    JVM学习笔记(一)——类的加载机制

    Java虚拟机(JVM)是Java程序运行的基础,它的核心组成部分之一就是类加载机制。类加载机制负责将Java源代码编译成的.class文件转换为内存中的数据结构,以便程序可以执行。本篇将深入探讨类加载机制的原理和过程。 ...

    JVM学习资料+笔记

    1. 类加载机制:JVM按照类加载器、双亲委派模型、验证、准备、解析、初始化等步骤加载类。了解这一过程有助于理解类的生命周期和防止类冲突。 2. 字节码执行引擎:JVM通过解释器和即时编译器(JIT)来执行字节码,...

    JVM学习笔记核心知识点整理

    ### JVM学习笔记核心知识点整理 #### 一、引言与背景 随着软件开发技术的不断发展,Java作为一种广泛应用的编程语言,其背后的核心技术——Java虚拟机(JVM)的重要性日益凸显。掌握JVM不仅可以帮助开发者更好地理解...

    狂神说JVM探究.rar

    2. **类加载机制**: - 类的生命周期包括加载、验证、准备、初始化和卸载五个阶段。 - 双亲委派模型:类加载器在加载类时,会将任务委托给父类加载器,直到Bootstrap ClassLoader。 3. **内存区域**: - 程序...

    jvm学习笔记

    《JVM学习笔记》 Java虚拟机(JVM)是Java平台的核心组成部分,它负责运行所有的Java应用程序。这篇笔记将深入探讨JVM的工作原理、内存管理、类加载机制以及优化策略,帮助读者全面理解JVM并提升Java程序的性能。 ...

    学习笔记之java虚拟机

    - 存储已被虚拟机加载的类信息、常量、静态变量等数据。 - 可选择实现垃圾回收机制。 - 在HotSpot虚拟机中,通常被称为“永久代”。 6. **运行时常量池**: - 是方法区的一部分,用于存放编译期间产生的各种...

Global site tag (gtag.js) - Google Analytics