JVM类加载机制详解 JVM类加载过程

转载 2018年04月15日 10:26:53

首先,在代码编译后,就会生成JVM(Java虚拟机)能够识别的二进制字节流文件(*.class)。而JVM把Class文件中的类描述数据从文件加载到内存,并对数据进行校验、转换解析、初始化,使这些数据最终成为可以被JVM直接使用的Java类型,这个说来简单但实际复杂的过程叫做JVM的类加载机制


Class文件中的“类”从加载到JVM内存中,到卸载出内存过程有七个生命周期阶段。类加载机制包括了前五个阶段。

如下图所示:


其中,加载、验证、准备、初始化、卸载的开始顺序是确定的,注意,只是按顺序开始,进行与结束的顺序并不一定。解析阶段可能在初始化之后开始。


另外,类加载无需等到程序中“首次使用”的时候才开始,JVM预先加载某些类也是被允许的。(类加载的时机


一、类的加载

我们平常说的加载大多不是指的类加载机制,只是类加载机制中的第一步加载。在这个阶段,JVM主要完成三件事:

1、通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件)。而获取的方式,可以通过jar包、war包、网络中获取、JSP文件生成等方式。

2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。这里只是转化了数据结构,并未合并数据。(方法区就是用来存放已被加载的类信息,常量,静态变量,编译后的代码的运行时内存区域)

3、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。这个Class对象并没有规定是在Java堆内存中,它比较特殊,虽为对象,但存放在方法区中。


二、类的连接

类的加载过程后生成了类的java.lang.Class对象,接着会进入连接阶段,连接阶段负责将类的二进制数据合并入JRE(Java运行时环境)中。类的连接大致分三个阶段。

1、验证:验证被加载后的类是否有正确的结构,类数据是否会符合虚拟机的要求,确保不会危害虚拟机安全。

2、准备:为类的静态变量(static filed)在方法区分配内存,并赋默认初值(0值或null值)。如static int a = 100;

静态变量a就会在准备阶段被赋默认值0。

对于一般的成员变量是在类实例化时候,随对象一起分配在堆内存中。

另外,静态常量(static final filed)会在准备阶段赋程序设定的初值,如static final int a = 666;  静态常量a就会在准备阶段被直接赋值为666,对于静态变量,这个操作是在初始化阶段进行的。

3、解析:将类的二进制数据中的符号引用换为直接引用。


三、类的初始化

类初始化是类加载的最后一步,除了加载阶段,用户可以通过自定义的类加载器参与,其他阶段都完全由虚拟机主导和控制。到了初始化阶段才真正执行Java代码。

类的初始化的主要工作是为静态变量赋程序设定的初值。

如static int a = 100;在准备阶段,a被赋默认值0,在初始化阶段就会被赋值为100。


Java虚拟机规范中严格规定了有且只有五种情况必须对类进行初始化

1、使用new字节码指令创建类的实例,或者使用getstatic、putstatic读取或设置一个静态字段的值(放入常量池中的常量除外),或者调用一个静态方法的时候,对应类必须进行过初始化。

2、通过java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则要首先进行初始化。

3、当初始化一个类的时候,如果发现其父类没有进行过初始化,则首先触发父类初始化。

4、当虚拟机启动时,用户需要指定一个主类(包含main()方法的类),虚拟机会首先初始化这个类。

5、使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、RE_invokeStatic的方法句柄,并且这个方法句柄对应的类没有进行初始化,则需要先触发其初始化。


注意,虚拟机规范使用了“有且只有”这个词描述,这五种情况被称为“主动引用”,除了这五种情况,所有其他的类引用方式都不会触发类初始化,被称为“被动引用”。


被动引用的例子一:

通过子类引用父类的静态字段,对于父类属于“主动引用”的第一种情况,对于子类,没有符合“主动引用”的情况,故子类不会进行初始化。代码如下:

//父类  
public class SuperClass {  
    //静态变量value  
    public static int value = 666;  
    //静态块,父类初始化时会调用  
    static{  
        System.out.println("父类初始化!");  
    }  
}  
  
//子类  
public class SubClass extends SuperClass{  
    //静态块,子类初始化时会调用  
    static{  
        System.out.println("子类初始化!");  
    }  
}  
  
//主类、测试类  
public class NotInit {  
    public static void main(String[] args){  
        System.out.println(SubClass.value);  
    }  
}  

输出结果:


被动引用的例子之二:

通过数组来引用类,不会触发类的初始化,因为是数组new,而类没有被new,所以没有触发任何“主动引用”条款,属于“被动引用”。代码如下:

//父类  
public class SuperClass {  
    //静态变量value  
    public static int value = 666;  
    //静态块,父类初始化时会调用  
    static{  
        System.out.println("父类初始化!");  
    }  
}  
  
//主类、测试类  
public class NotInit {  
    public static void main(String[] args){  
        SuperClass[] test = new SuperClass[10];  
    }  
} 

没有任何结果输出!

被动引用的例子之三:

刚刚讲解时也提到,静态常量在编译阶段就会被存入调用类的常量池中,不会引用到定义常量的类,这是一个特例,需要特别记忆,不会触发类的初始化!

//常量类  
public class ConstClass {  
    static{  
        System.out.println("常量类初始化!");  
    }  
      
    public static final String HELLOWORLD = "hello world!";  
}  
  
//主类、测试类  
public class NotInit {  
    public static void main(String[] args){  
        System.out.println(ConstClass.HELLOWORLD);  
    }  
}  


Java内存模型 —— 深入JVM

-
  • 1970年01月01日 08:00

JVM类加载机制详解(一)JVM类加载过程

首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1、什么是类加载?类加载的时机? 2、什么是类初始化?什么时候进行类初始化? 3、什么时候会为变量分配内存? 4、什么时候会为变量赋默认初值...
  • zhangliangzi
  • zhangliangzi
  • 2016-05-05 16:07:06
  • 22122

JVM(四)—一道面试题搞懂JVM类加载机制

有这样一道面试题: class Singleton{ private static Singleton singleton = new Singleton(); public s...
  • noaman_wgs
  • noaman_wgs
  • 2017-07-05 19:35:20
  • 2880

【深入理解JVM】:类加载机制

概述虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。与那些在编译时需要进行链接工作的语言不同,...
  • u011080472
  • u011080472
  • 2016-05-06 10:13:25
  • 3704

JVM(三):类加载机制(类加载过程和类加载器)

使用java编译器可以把java代码编译为存储字节码的Class文件,使用其他语言的编译器一样可以把程序代码翻译成Class文件,java虚拟机不关心Class的来源是何种语言。如图所示: 在Cla...
  • boyupeng
  • boyupeng
  • 2015-08-25 15:38:32
  • 22928

【Java面试整理之JVM】深入理解JVM结构、类加载机制、垃圾回收GC原理、JVM内存分配策略、JVM内存泄露和溢出

一、前言最近要准备找工作,JVM肯定是跑不掉的面试内容,所以把JVM相关的内容拿来认真学习一遍,整理成自己能够快速消化的提纲,方便随时可以调用。主要分JVM结构、类加载机制、垃圾回收GC原理、JVM内...
  • shengmingqijiquan
  • shengmingqijiquan
  • 2017-08-23 17:11:40
  • 762

java内存模型与类加载机制

Java内存模型,是指多线程并发时,将内存分为主内存和工作内存,每条线程运行时拥有自己的内存区域。 Java内存模型主要从三个特性进行解释。 一是原子性,线程工作时,一共八个原子操作,...
  • dragon_cat_han
  • dragon_cat_han
  • 2016-08-08 13:06:57
  • 1844

【深入Java虚拟机】之四:类加载机制

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。 其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这...
  • mmc_maodun
  • mmc_maodun
  • 2014-01-08 00:09:27
  • 45809

JVM类加载机制详解(二)类加载器与双亲委派模型

在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1、通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件)。而获取的方式...
  • zhangliangzi
  • zhangliangzi
  • 2016-05-07 21:19:35
  • 9357

深入JVM类加载机制

类加载的流程以及双亲委派模型
  • dd864140130
  • dd864140130
  • 2015-11-13 14:13:19
  • 5372
收藏助手
不良信息举报
您举报文章:JVM类加载机制详解 JVM类加载过程
举报原因:
原因补充:

(最多只允许输入30个字)