jvm虚拟机生命周期(一)

jvm虚拟机生命周期

当我们编写一个java的源文件后,经过编译会生成一个后缀名为class的文件,这种文件叫做字节码文件,只有这种字节码文件才能够在java虚拟机中运行,java类的生命周期就是指一个class文件从加载到卸载的全过程。

一个java类的完整的生命周期会经历加载连接初始化使用、和卸载五个阶段,如图所示:

这里写图片描述

1.加载

Java虚拟机把Class类文件加载到内存中,并对Class文件中的数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程。

加载阶段,java虚拟机需要完成以下3件事:
1. 通过一个类的全限定名来获取定义此类的二进制字节流。
1. 将定义类的二进制字节流所代表的静态存储结构转换为方法区的运行时数据结构。
1. 在java堆中生成一个代表该类的java.lang.Class对象,作为方法区数据的访问入口。

2.验证

验证连接阶段的第一步,其目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机的安全,如果验证失败,会抛出java.lang.VerifyError异常。

验证阶段的主要工作有:
1. 文件格式验证:验证Class文件魔数、主次版本、常量池、类文件本身等等。
1. 元数据验证:主要是对字节码描述的信息进行语义分析,包括是否有父类、是否是抽象类、是否是接口、是否继承了不允许被继承的类(final类)、是否实现了父类或者接口的方法等等。
1. 字节码验证:是整个验证过程中最复杂的,主要进行数据流和控制流分析,如保证跳转指令不会跳转到方法体之外的字节码指令、数据类型转换安全有效等。
1. 符号引用验证:发生在虚拟机将符号引用转化为直接引用的时候(连接第三阶段-解析阶段进行符号引用转换为直接引用),符号引用验证的目的是确保解析动作能正常执行,如果无法通过符号引用验证,则会抛出java.lang.IncompatibleClassChangeError异常的子类异常,如java.lang.IllegalAccessError、java.lang.NoSuchFieldError、java.lang.NoSuchMethodError等。

验证阶段对于虚拟机来说非常重要,但是不是一个必需的阶段,如果所运行的代码已经反复被使用和验证过了,可以通过-Xverify:none参数关闭大部分的验证措施,以提高虚拟机时间时间。

3.准备

准备阶段是正式为类变量(静态变量,注意不是实例变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。

对于普通非final的类变量,如public static int value = 123;在准备阶段过后的初始值是0(数据类型的零值),而不是123,而把123赋值给value是在初始化阶段才进行的动作。

对于final的类变量,即常量,如public static final int value =123;在准备阶段过程的初始值直接就是123了,不需要准备为零值。

4.解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。

符号引用(SymbolicReference):以一组符号来描述所引用的目标,与虚拟机内存布局无关,引用的目标不一定已经被加载到虚拟机内存中。

直接引用(DirectReference):可以直接指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄。直接引用和虚拟机实现的内存布局相关,同一个符号引用在不同虚拟机上翻译处理的直接引用不一定相同,如果有了直接引用,则引用的目标对象必须已经被加载到虚拟机内存中。
解析的动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行解析。

5.初始化

初始化是类使用前的最后一个阶段,在初始化阶段java虚拟机真正开始执行类中定义的java程序代码。

Java程序对类的使用方式可分为两种
1. 主动使用
1. 被动使用

jvm虚拟机规范严格规定了有且只有以下几种情况必须立即对类进行初始化:

  1. 创建类的实例:new,反射等。
  2. 调用某个类的静态方法
  3. 访问某个类或接口的静态属性
  4. 使用反射方式来强制创建某个类或接口对应的Class的对象。
  5. 初始化某个类的子类,该子类的所有父类都会被初始化。
  6. 直接使用java命令来运行某个类,当运行某个主类时,程序会先初始化该主类。

上述几种情况称为对一个类的主动引用,除此之外的引用方式都不会触发初始化,称为被动引用

6.使用

当初始化完成之后,java虚拟机就可以执行Class的业务逻辑指令,通过堆中java.lang.Class对象的入口地址,调用方法区的方法逻辑,最后将方法的运算结果通过方法返回地址存放到方法区或堆中。

7.卸载

当对象不再被使用时,java虚拟机的垃圾收集器将会回收堆中的对象,方法区中不再被使用的Class也要被卸载,否则方法区(Sun HotSpot永久代)会内存溢出。

Java虚拟机规定只有当加载该类型的类加载器实例为unreachable状态时,当前被加载的类型才被卸载.启动类加载器实例永远为reachable状态,由启动类加载器加载的类型可能永远不会被卸载,类型卸载仅仅是作为一种减少内存使用的性能优化措施存在的,具体和虚拟机实现有关,对开发者来说是透明的.

卸载自定义来加载器加载的类的可靠做法为:
1. 每次创建特定类加载器的新实例来加载指定类型的不同版本,这种使用场景下,一般就要牺牲缓存特定类型的类加载器实例以带来性能优化的策略了.
1. 对于指定类型已经被加载的版本, 会在适当时机达到unreachable状态,被unload并垃圾回收.每次使用完类加载器特定实例后(确定不需要再使用时), 将其显示赋为null, 这样可能会比较快的达到jvm 规范中所说的类加载器实例unreachable状态, 增大已经不再使用的类型版本被尽快卸载的机会.

生命周期结束

在如下几种情况下,Java虚拟机将结束生命周期
1. 执行了System.exit()方法主动停止jvm运行
1. 程序正常执行结束
1. 程序在执行过程中遇到了异常或错误而异常终止
1. 由于操作系统出现错误而导致Java虚拟机进程终止

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值