码迷,mamicode.com
首页 > 编程语言 > 详细

【Java】【JVM】类的生命周期【整理】

时间:2017-12-14 15:48:04      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:等于   自己   .class   对比   结束   完成   数据结构   stc   动态绑定   

参考如下两篇并整理。

https://www.cnblogs.com/dongguacai/p/5860241.html

https://www.cnblogs.com/ITtangtang/p/3978102.html

 

类的生命周期是从被加载到虚拟机内存中开始,到卸载出内存结束。过程共有七个阶段。

1.加载---2.验证---3.准备---3.解析---5.初始化---6.使用---7.卸载

加载---(链接)----验证(校验、检查)----准备----解析-----初始化----使用-----卸载

 技术分享图片

其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。

在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。

另外注意这里的几个阶段是按顺序开始而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。


 

【1.加载(装载)】

在装载阶段,虚拟机需要完成以下3件事情
(1) 通过一个类的全限定名来获取定义此类的二进制字节流。
(2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
(3) 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。
虚拟机规范中并没有准确说明二进制字节流应该从哪里获取以及怎样获取,这里可以通过定义自己的类加载器去控制字节流的获取方式。

 

【2.验证(校验、检查)】

  虚拟机如果不检查输入的字节流,对其完全信任的话,很可能会因为载入了有害的字节流而导致系统奔溃。

 

  1.文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
  2.元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。
  3.字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
  4.符号引用验证:确保解析动作能正确执行。
  验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,

  那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

 

 

【3.准备】————为类的静态变量配内存,并将其初始化为默认值

 

这个阶段正式为类变量(被static修饰的变量)分配内存并设置类变量初始值,这个内存分配是发生在方法区中。

1、注意这里并没有对实例变量进行内存分配,实例变量将会在对象实例化时随着对象一起分配在JAVA堆中

2、这里设置的初始值,通常是指数据类型的‘“零”值。

  public static int value = 123;

  value在准备阶段过后的初始值为0而不是123,而把value赋值的putstatic指令将在初始化阶段才会被执行

【4.解析】

 

【5.初始化】

  详细见此

  【1】在如下三个场景(能生成四个字节码指令的场景),如果类还未初始化,则初始化。

        (4个指令【new、getstatic、putstatic、invokestatic】)

   A.new

      new Test();

   B.读取或设置类的静态变量      

      int b=Test.a;
      Test.a=b;

   C.调用静态函数

      Test.doSomething();

  【2】反射调用。

      Class.forName(“com.mengdd.Test”);

  【3】子类初始化,要先初始化父类(所有父类)。

  【4】虚拟机启动时,要初始化主类。直接使用java.exe命令来运行某个主类。

 

  只有上述四种情况会触发初始化,也称为对一个类进行主动引用。

   除此以外,有其他方式都不会触发初始化,称为被动引用。

注意:

(1)子类引用父类的静态变量,不会导致子类初始化。

(2)通过数组定义引用类,不会触发此类的初始化

(3)引用常量时,不会触发该类的初始化

举例:

(1)子类引用父类的静态变量,不会导致子类初始化。

public class SupClass
{
    public static int a = 123;
    
    static
    {
        System.out.println("supclass init");
    }
}

public class SubClass extends SupClass
{
    static
    {
        System.out.println("subclass init");
    }
}

public class Test
{
    public static void main(String[] args)
    {
        System.out.println(SubClass.a);
    }
}

执行结果:

supclass init
123

(2)通过数组定义引用类,不会触发此类的初始化

public class SupClass
{
    public static int a = 123;
    
    static
    {
        System.out.println("supclass init");
    }
}

public class Test
{
    public static void main(String[] args)
    {
        SupClass[] spc = new SupClass[10];
    }
}

执行结果:

 

(3)引用常量时,不会触发该类的初始化

public class ConstClass
{
    public static final String A=  "MIGU";
    
    static
    {
        System.out.println("ConstCLass init");
    }
}

public class TestMain
{
    public static void main(String[] args)
    {
        System.out.println(ConstClass.A);
    }
}

执行结果:

MIGU

final修饰某个类变量时,它的值在编译时就已经确定好放入常量池了,所以在访问该类变量时,等于直接从常量池中获取,并没有初始化该类

初始化的步骤

1、如果该类还没有加载和连接,则程序先加载该类并连接。

2、如果该类的直接父类没有加载,则先初始化其直接父类。

3、如果类中有初始化语句,则系统依次执行这些初始化语句。

在第二个步骤中,如果直接父类又有直接父类,则系统会再次重复这三个步骤来初始化这个父类,

依次类推,JVM最先初始化的总是java.lang.Object类

当程序主动使用任何一个类时,系统会保证该类以及所有的父类都会被初始化。

【6.使用】

 

【7.卸载】

 

【Java】【JVM】类的生命周期【整理】

标签:等于   自己   .class   对比   结束   完成   数据结构   stc   动态绑定   

原文地址:http://www.cnblogs.com/CESC4/p/8037858.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!